vue3 封装公共弹窗函数

news2024/11/17 17:52:54

前言:

博主封装了一个公共弹窗函数接收四个参数,(title:弹窗标题, ContentComponent:弹窗中显示的组件内容, opt:接收弹窗本身的属性和props, beforeSure:点击确定做的操作(请求后端接口))

封装的公共函数:

import { defineComponent, h, ref, getCurrentInstance } from "vue-demi";
import Vue from "vue";
import { isFunction, isUndefined, noop, isPlainObject } from "lodash";

const WRAPPED = "wrapped";

function generateDialogComponent(wrapped, opt, listeners = {}) {
  return defineComponent({
    setup() {
      const loading = ref(false);
      const vm = getCurrentInstance();
      const visible = opt.visible; // Ref<boolean>
      const closeable = opt.closeable; // Ref<boolean>
      const showCancelButton = isUndefined(opt.dialog.showCancelButton)
        ? true
        : opt.dialog.showCancelButton;
      const showSureBtn =
        isUndefined(opt.dialog.showSureBtn) &&
        isUndefined(opt.dialog.showSureButton)
          ? true
          : opt.dialog.showSureBtn || opt.dialog.showSureButton;
      const showFooter = isUndefined(opt.dialog.showFooter)
        ? true
        : opt.dialog.showFooter;
      const confirmButtonText = opt.dialog.confirmButtonText || "确定";
      const cancelButtonText = opt.dialog.cancelButtonText || "取消";

      return () => {
        const sure = listeners.sure || (() => Promise.resolve());
        const cancel = listeners.cancel || noop;
        const destroy = listeners.destroy || noop;
        // footer
        const sureBtn = h(
          "el-button",
          {
            props: {
              size: "mini",
              type: "primary",
              loading: loading.value,
            },
            on: {
              click: () => {
                loading.value = true;
                const wrappedVm = vm.proxy.$refs[WRAPPED];
                return sure(wrappedVm)
                  .then(() => {
                    visible.value = false;
                  })
                  .finally(() => (loading.value = false));
              },
            },
          },
          confirmButtonText
        );
        const cancelBtn = h(
          "el-button",
          {
            props: {
              size: "mini",
            },
            on: {
              click: () => {
                visible.value = false;
              },
            },
          },
          cancelButtonText
        );
        const footer = h(
          "div",
          {
            slot: "footer",
            style: {
              display: "flex",
              justifyContent: "space-between",
            },
          },
          [
            h("div", [opt.dialog?.leftFooter?.()]),
            h("div", [
              closeable.value && showCancelButton && cancelBtn,
              showSureBtn && sureBtn,
            ]),
          ]
        );
        return h(
          "el-dialog",
          {
            props: {
              closeOnClickModal: false,
              visible: visible.value,
              ...opt.dialog,
              closeOnClickModal: closeable.value,
              closeOnPressEscape: closeable.value,
              showClose: closeable.value,
            },
            on: {
              "update:visible": (val) => {
                visible.value = val;
              },
              closed: () => {
                cancel();
                destroy();
              },
            },
          },
          [
            h("div", { style: { padding: "20px" } }, [
              h(wrapped, {
                ref: WRAPPED,
                attrs: Object.assign({}, opt.props),
                on: {
                  close: sure, // 组件内部可以通过 emit('close') 来关闭弹窗
                },
              }),
            ]),
            showFooter && footer,
          ]
        );
      };
    },
  });
}

function openDialog(title, ContentComponent, opt, beforeSure) {
  const defaultOpt = {
    dialog: {},
    props: {},
  };
  // 参数格式化
  if (isUndefined(opt)) {
    opt = defaultOpt;
  }
  if (isFunction(opt)) {
    opt = defaultOpt;
    beforeSure = opt;
  }
  if (!isFunction(beforeSure)) {
    beforeSure = (vm) => vm.submit?.();
  }

  if (isPlainObject(opt)) {
    if (isUndefined(opt.props)) {
      opt = {
        ...opt,
        props: opt,
      };
    }
  }

  opt.dialog = opt.dialog || opt || {};
  opt.dialog.title = title;

  const mountComponent = ($vueconfig) => {
    const vm = new Vue($vueconfig);
    const anchor = document.createElement("div");
    document.body.appendChild(anchor);
    vm.$mount(anchor);
    return () => {
      vm.$destroy();
      document.body.removeChild(vm.$el);
    };
  };

  // 控制 dialog 显隐
  const visible = ref(false);
  const closeDialog = () => {
    visible.value = false;
  };

  // 控制是否可以关闭
  const closeable = ref(true);
  // 不可关闭弹窗
  const freeze = () => {
    closeable.value = false;
  };
  // 可关闭弹窗
  const unfreeze = () => {
    closeable.value = true;
  };

  const wait = new Promise((resolve, reject) => {
    let disposer = null;
    const destroy = () => isFunction(disposer) && disposer();
    const cancel = () => {
      reject(new Error("cancel"));
    };
    const sure = async (wrappedComp) => {
      const promise = await beforeSure(wrappedComp);
      resolve(promise);
    };
    disposer = mountComponent(
      generateDialogComponent(
        ContentComponent,
        { ...opt, visible, closeable },
        { sure, cancel, destroy }
      )
    );
    // 打开弹窗
    setTimeout(() => (visible.value = true), 20);
  });

  return {
    close: closeDialog,
    promise: wait,
    freeze,
    unfreeze,
  };
}

export function pickByDialog(...args) {
  const { promise } = openDialog(...args);
  return promise;
}

/**
 * 让 pickByDialog 静默失败, 并且提供一个手动关闭弹窗的函数
 * @Returns { close }
 */
export const openByDialog = (...args) => {
  const { close, freeze, unfreeze, promise } = openDialog(...args);
  promise.catch(() => {
    // no throw error
  });
  return {
    close,
    freeze,
    unfreeze,
  };
};

部分代码解释:

generateDialogComponent函数解释:

  1. generateDialogComponent函数定义了一个组件,并返回该组件。
  2. 在组件的setup函数中,首先定义了一些变量和常量,包括:
    • loading:一个用于表示加载状态的响应式变量(Ref)。
    • vm:当前组件实例的引用。
    • visible:一个响应式变量,表示对话框的可见性。
    • closeable:一个响应式变量,表示对话框是否可关闭。
    • showCancelButton:一个布尔值,表示是否显示取消按钮,默认为true
    • showSureBtn:一个布尔值,表示是否显示确定按钮,默认为true
    • showFooter:一个布尔值,表示是否显示底部内容,默认为true
    • confirmButtonText:确定按钮的文本,默认为"确定"。
    • cancelButtonText:取消按钮的文本,默认为"取消"。
  1. 返回一个函数,该函数使用Vue 3的Composition API语法,作为组件的渲染函数(render function)。
  2. 渲染函数返回一个el-dialog组件,该组件是一个基于Element UI库的对话框组件。
  3. el-dialog组件的属性包括:
    • closeOnClickModal:控制是否在点击模态框时关闭对话框,根据closeable的值进行设置。
    • visible:控制对话框的可见性,根据visible的值进行设置。
    • ...opt.dialog:将opt.dialog对象中的所有属性都作为el-dialog组件的属性。
    • closeOnClickModal:控制是否在点击模态框时关闭对话框,根据closeable的值进行设置。
    • closeOnPressEscape:控制是否在按下Esc键时关闭对话框,根据closeable的值进行设置。
    • showClose:控制是否显示关闭按钮,根据closeable的值进行设置。
  1. el-dialog组件的事件包括:
    • update:visible:当对话框的可见性发生变化时,更新visible的值。
    • closed:当对话框关闭时,触发canceldestroy函数。
  1. el-dialog组件的插槽包括:
    • 默认插槽:包含一个具有样式{ padding: "20px" }div元素,其中包含了wrapped组件。
    • showFootertrue时,底部插槽:包含一个具有样式{ display: "flex", justifyContent: "space-between" }div元素,其中包含了底部内容。
  1. 返回生成的组件。

openDialog的函数解释:

  1. openDialog函数接受四个参数:title(对话框标题),ContentComponent(对话框内容组件),opt(可选配置对象),和beforeSure(可选的确定按钮点击前的回调函数)。
  2. 定义了一个名为defaultOpt的默认配置对象,包含dialogprops两个属性。
  3. 对传入的optbeforeSure进行格式化处理:
    • 如果optundefined,则将其设置为defaultOpt的值。
    • 如果opt为函数,则将其设置为defaultOpt的值,并将beforeSure设置为该函数。
    • 如果beforeSure不是函数,则将其设置为一个默认函数,该函数会调用传入的组件实例的submit方法(如果存在)。
  1. opt进行进一步处理:
    • 如果opt是普通对象且没有props属性,则将opt的值复制给opt.props
  1. opt.dialog设置为optopt.dialog的值,并将title设置为opt.dialog.title
  2. 定义了一个名为mountComponent的函数,用于将组件挂载到DOM上,并返回一个销毁函数。
    • 在函数内部,创建了一个新的Vue实例,并将其挂载到一个新创建的div元素上。
    • 将该div元素添加到document.body中。
    • 返回一个函数,该函数在调用时会销毁Vue实例,并从document.body中移除该div元素。
  1. 创建了一个响应式的变量visible,用于控制对话框的显示和隐藏。
  2. 定义了一个closeDialog函数,用于关闭对话框。
  3. 创建了一个响应式的变量closeable,用于控制对话框是否可以关闭。
  4. 定义了freeze函数,将closeable设置为false,使对话框不可关闭。
  5. 定义了unfreeze函数,将closeable设置为true,使对话框可关闭。
  6. 创建了一个Promise对象wait,用于等待对话框的操作完成。
  7. wait的执行函数中,定义了一些内部函数和变量:

  • disposer:用于存储销毁函数的引用。
  • destroy函数:用于执行销毁函数。
  • cancel函数:用于拒绝Promise并抛出一个取消错误。
  • sure函数:在确定按钮点击时执行的回调函数,调用beforeSure函数并传入wrappedComp作为参数,并将返回的Promise解析为resolve的值。
  • disposer设置为调用mountComponent函数,并传入generateDialogComponent函数生成的对话框组件。
  • 使用setTimeout延迟20毫秒后,将visible设置为true,打开对话框。

  1. 返回一个对象,包含以下属性和方法:

  • close:关闭对话框的方法。
  • promise:返回等待对话框操作完成的Promise对象。
  • freeze:使对话框不可关闭的方法。
  • unfreeze:使对话框可关闭的方法。

使用方法例子如下

例子一

const { close } = openByDialog(
        "自定义列表",
        Setting2,
        {
          props: menuProps,
          dialog: {
            width: "980px",
            confirmButtonText: "保存",
            leftFooter: () =>
              h(
                "el-button",
                {
                  style: { color: "#2783fe" },
                  props: {
                    size: "mini",
                    type: "text",
                    loading: reseting.value,
                  },
                  on: {
                    click: () => doReset(),
                  },
                },
                "恢复系统默认设置"
              ),
          },
        },
        async (componentWrapper) => {
          const updatedColumns = await componentWrapper?.updateColumnSetting();
          this.emitChangeColumns2(updatedColumns);
        }
      );

例子二

//组件弹窗测试
      async doImportLog() {
        const [cancel, blob] = await to(
          pickByDialog(
            "弹窗导出测试",
            getLogComp(this), //这个是组件
            {
              dialog: { width: "35%" },
              // props: { value: this.value },
              // on: {
              //   input: (val) => {
              //     this.value = val
              //   },
              // },
            },
            async (vm) => {
              const [changeDateBt, changeDateEt] = vm.date;
              console.log("changeDateBt", changeDateBt);
              console.log("changeDateEt", changeDateEt);
            }
          )
        );
        if (cancel) {
          this.$message.info(this.$tof("cancel"));
          return;
        }
        const curDate = dayjs().format("YYYYMMDD");
        console.log("curDate", curDate);
        saveAs(blob.data, this.$tof("file_name", { curDate }));
      },


  function getLogComp(vm) {
    return {
      data() {
        return {
          date: [],
        };
      },
      render(h) {
        return h("el-row", { style: { margin: "100px 50px" } }, [
          h(
            "el-col",
            { style: { lineHeight: "36px" }, attrs: { span: 8 } },
            "导出范围时间"
          ),
          h("el-col", { attrs: { span: 16 } }, [
            h("el-date-picker", {
              attrs: {
                type: "daterange",
                rangeSeparator: "-",
                startPlaceholder: "开始日期",
                endPlaceholder: "结束日期",
                value: this.date,
                valueFormat: "yyyy-MM-dd",
              },
              style: { width: "auto !important" },
              on: {
                input: (val) => {
                  this.date = val;
                },
              },
            }),
          ]),
        ]);
      },
    };
  }

例子三

//组件弹窗测试222
      async doAdd() {
        const [cancel] = await to(
          pickByDialog(
            "新增客户",
            GroupCreate, //组件
            {
              dialog: {
                width: "80%",
                confirmButtonText: "保存",
                leftFooter: () =>
                  h(
                    "el-button",
                    {
                      style: { color: "#2783fe" },
                      props: {
                        size: "mini",
                        type: "text",
                        loading: false,
                      },
                      on: {
                        click: () => doReset(),
                      },
                    },
                    "恢复系统默认设置"
                  ),
              },
              props: {},
            },
            async (vm) => {
              console.log("测试点击确定", vm);
            }
          )
        );
        if (cancel) {
          this.$message.info("已取消");
          return;
        }
        function doReset() {
          console.log("测试左边操作");
        }
      },


    GroupCreate组件:

    
    <template>
  <div>
    <CollapsePanel :show-header="true">
      <template #panel-button>
        <el-button
          size="small"
          type="primary"
          :loading="loading"
          @click="doInquiry"
        >
          搜索
        </el-button>
      </template>
      <template #panel-main>
        <el-form
          ref="filterForm"
          :inline="true"
          :model="schemaModel"
          :max-height="200"
          class="list-schema-form"
          label-position="top"
        >
          <el-row
            v-for="(row, index) in schemaList"
            :key="index"
            v-bind="layout"
          >
            <el-col
              v-for="{ rules, label, prop, component, ...attrs } in row"
              :key="prop"
              :span="12"
            >
              <el-form-item v-if="prop" v-bind="{ label, rules, prop }">
                {{ component }}
                <component
                  :is="`el-${component}`"
                  v-model="schemaModel[prop]"
                  :placeholder="component + '_placeholder'"
                  v-bind="attrs"
                >
                  <el-option
                    v-for="ops in schemaOptions[prop]"
                    :key="ops.value"
                    v-bind="ops"
                  />
                </component>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
      </template>
    </CollapsePanel>

    <CollapsePanel :auto-height="true">
      <template #panel-main>
        <el-table
          ref="tableRef"
          v-loading="loading"
          :data="list"
          border
          stripe
          max-height="550"
        >
          <el-table-column type="selection" fixed="left" width="40" />
          <el-table-column
            type="index"
            width="60"
            fixed="left"
            :label="'序号'"
          />
          <el-table-column
            v-for="{ field, render, ...attrs } in columns"
            :key="field"
            v-bind="attrs"
          >
            <template #default="scope">
              <field-render :render="render" :scope="scope" :field="field" />
            </template>
          </el-table-column>
        </el-table>
        <div class="table-pagination">
          <pagination
            :limit="pageSize"
            :page="pageNum"
            :total="totalPages"
            @pagination="(pageNum = $event.page) && (pageSize = $event.limit)"
          />
        </div>
      </template>
    </CollapsePanel>
  </div>
</template>

<script>
  // import { customerinfoFindCustByCustNameOrCustCodeToCommodity } from '@/api/commodity/price'

  import to from "await-to-js";
  import { snakeCase } from "lodash";

  export default {
    name: "GroupCreate",
    components: {
      FieldRender: {
        functional: true,
        props: {
          scope: {
            type: Object,
            default: () => ({}),
          },
          render: Function,
          field: String,
        },
        render: (h, { props }) => {
          const { render, scope, field } = props;
          return render
            ? render(h, { ...scope, field })
            : h("span", null, scope.row[field]);
        },
      },
    },
    data(vm) {
      return {
        ...getSchemaList(vm),
        list: [],
        columns: getColumList(vm),
        pageNum: 1,
        pageSize: 10,
        totalPages: 0,
        loading: false,
        layout: {
          gutter: 60,
          justify: "start",
        },
      };
    },
    watch: {
      pageNum: {
        handler() {
          this.doInquiry();
        },
      },
      pageSize: {
        handler() {
          this.doInquiry();
        },
      },
    },
    async created() {
      // const options = await this.$ops({});
      // Object.assign(this.schemaOptions, options);

      this.doInquiry();
    },
    methods: {
      async doInquiry() {
        console.log("测试");
        // this.loading = true
        // const [err, data] = await to(
        //   customerinfoFindCustByCustNameOrCustCodeToCommodity(
        //     Object.assign(this.schemaModel, {
        //       page: this.pageNum - 1,
        //       size: this.pageSize,
        //     })
        //   )
        // ).finally(() => (this.loading = false))
        // if (err) {
        //   return
        // }

        // const { content, totalElements = 5 } = data
        // this.totalPages = +totalElements
        // this.list = content.map((i) => ({
        //   custCode: i.customerCode,
        //   custName: i.customerName,
        // }))
      },
      doReset() {
        this.schemaModel = {};
      },
      doDelete() {},
      doAdd() {},
      async doSave() {
        const [err] = await to(this.$refs["filterForm"].validate());
        if (err) {
          return;
        }
      },
      doBack() {
        this.$store.dispatch("tabsBar/delVisitedRoute", this.$route.fullPath);
        this.$router.back();
      },
    },
  };

  function getColumList(vm) {
    const COLUM_FIELDS = ["custCode", "custName"];
    const FORM_FIELDS_NAME = {
      custName: "客户名称",
      custCode: "客户编码",
    };

    const colProperties = {};
    return COLUM_FIELDS.map((prop) =>
      Object.assign(
        { prop, label: FORM_FIELDS_NAME[prop], field: prop },
        colProperties[prop] || {
          sortable: true,
        }
      )
    );
  }

  function getSchemaList(vm) {
    const FORM_FIELDS = ["custCode", "custName"];
    const FORM_FIELDS_NAME = {
      custName: "客户名称",
      custCode: "客户编码",
    };
    let properties = {
      custCode: {},
      custName: {},
    };
    const array = FORM_FIELDS.map((prop) => {
      const label = FORM_FIELDS_NAME[prop];
      const attrs = properties[prop];

      return {
        prop,
        label,
        clearable: true,
        filterable: true,
        component: "input",
        ...attrs,
      };
    });

    const schemaList = [array];
    return {
      schemaList,
      schemaModel: { custStatus: ["20"], custCode: "", custNameList: [] },
      schemaOptions: { status: [] },
    };
  }
</script>

<style lang="scss" scoped>
  ::v-deep .el-button--text {
    color: #409eff;
    font-size: 13px;
  }
  .total-number {
    color: #f55448;
  }
</style>

例子四

 async doAdd2() {
        openByDialog(
          "测试表单",
          FormTest,
          {
            props: {
              isShowCol: true,
            },
          },
          async (componentWrapper) => {
            await componentWrapper?.$children[0].validate();
            console.log("componentWrapper的数据", componentWrapper);
            componentWrapper.ruleForm.date1 = dayjs(
              componentWrapper.ruleForm.date1
            ).format("YYYYMMDD");

            let payload = componentWrapper.ruleForm;

            return await this.fetchData(payload);
          }
        );
      },


FormTest组件
<template>
  <el-form
    :model="ruleForm"
    :rules="rules"
    ref="ruleFormRef"
    label-width="100px"
    class="demo-ruleForm"
  >
    <el-form-item label="活动名称" prop="name">
      <el-input v-model="ruleForm.name"></el-input>
    </el-form-item>
    <el-form-item label="活动区域" prop="region">
      <el-select v-model="ruleForm.region" placeholder="请选择活动区域">
        <el-option label="区域一" value="shanghai"></el-option>
        <el-option label="区域二" value="beijing"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="活动时间" required>
      <el-col :span="11">
        <el-form-item prop="date1">
          <el-date-picker
            type="date"
            placeholder="选择日期"
            v-model="ruleForm.date1"
            style="width: 100%"
          ></el-date-picker>
        </el-form-item>
      </el-col>
      <el-col class="line" :span="2">-</el-col>
      <el-col :span="11">
        <el-form-item prop="date2">
          <el-time-picker
            placeholder="选择时间"
            v-model="ruleForm.date2"
            style="width: 100%"
          ></el-time-picker>
        </el-form-item>
      </el-col>
    </el-form-item>
    <el-form-item label="即时配送" prop="delivery">
      <el-switch v-model="ruleForm.delivery"></el-switch>
    </el-form-item>
    <!-- <el-form-item label="活动性质" prop="type">
        <el-checkbox-group v-model="ruleForm.type">
          <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
          <el-checkbox label="地推活动" name="type"></el-checkbox>
          <el-checkbox label="线下主题活动" name="type"></el-checkbox>
          <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
        </el-checkbox-group>
      </el-form-item> -->
    <el-form-item label="特殊资源" prop="resource">
      <el-radio-group v-model="ruleForm.resource">
        <el-radio label="线上品牌商赞助"></el-radio>
        <el-radio label="线下场地免费"></el-radio>
      </el-radio-group>
    </el-form-item>
    <el-form-item label="活动形式" prop="desc">
      <el-input type="textarea" v-model="ruleForm.desc"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm(ruleFormRef)">
        立即创建
      </el-button>
    </el-form-item>
  </el-form>
</template>

<script>
  import { defineComponent, ref } from "vue-demi";
  export default defineComponent({
    name: "ruleFormTest",
    props: {
      isShowCol: {
        type: Boolean,
        default: false,
      },
    },
    setup(props) {
      const ruleFormRef = ref();
      let ruleForm = ref({
        name: "",
        region: "",
        date1: "",
        date2: "",
        delivery: props.isShowCol,
        type: [],
        resource: "",
        desc: "",
      });
      let rules = ref({
        name: [
          { required: true, message: "请输入活动名称", trigger: "blur" },
          { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" },
        ],
        region: [
          { required: true, message: "请选择活动区域", trigger: "change" },
        ],
        date1: [
          {
            type: "date",
            required: true,
            message: "请选择日期",
            trigger: "change",
          },
        ],
        date2: [
          {
            type: "date",
            required: true,
            message: "请选择时间",
            trigger: "change",
          },
        ],
        type: [
          {
            type: "array",
            required: true,
            message: "请至少选择一个活动性质",
            trigger: "change",
          },
        ],
        resource: [
          { required: true, message: "请选择活动资源", trigger: "change" },
        ],
        desc: [{ required: true, message: "请填写活动形式", trigger: "blur" }],
      });

      const submitForm = async (formEl) => {
        console.log("formEl", formEl);
        if (!formEl) return;
        await formEl.validate((valid, fields) => {
          if (valid) {
            console.log("submit!");
          } else {
            console.log("error submit!", fields);
          }
        });
      };
      const resetForm = (formName) => {};
      // expose({ submitForm });
      return {
        ruleForm,
        rules,
        ruleFormRef,
        submitForm,
        resetForm,
      };
    },
  });
</script>

模拟一个异步返回

      fetchData(params) {
        return new Promise((resolve, reject) => {
          // 模拟异步请求
          setTimeout(() => {
            const data = { name: "John", age: 30, ...params };
            // 模拟请求成功
            resolve(data);
            // this.$message.error("请求接口失败");
            // 模拟请求失败
            // reject('请求失败');
          }, 1000);
        });
      },

填写完必填项发起后端请求,拿到数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1025525.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《动手学深度学习 Pytorch版》 7.3 网络中的网络(NiN)

LeNet、AlexNet和VGG的设计模式都是先用卷积层与汇聚层提取特征&#xff0c;然后用全连接层对特征进行处理。 AlexNet和VGG对LeNet的改进主要在于扩大和加深这两个模块。网络中的网络&#xff08;NiN&#xff09;则是在每个像素的通道上分别使用多层感知机。 import torch fr…

JumpServer开源堡垒机与爱可生云树数据库完成兼容性认证

近日&#xff0c;中国领先的开源软件提供商FIT2CLOUD飞致云宣布&#xff0c;JumpServer开源堡垒机已经完成与爱可生云树数据库软件的兼容性认证。经过双方联合测试&#xff0c;云树数据库软件&#xff08;简称&#xff1a;ActionDB&#xff09;V1.0与杭州飞致云信息科技有限公司…

前端提高代码质量-提升代码的可维护性

代码质量是一个非常重要的概念&#xff0c;它决定了代码的可读性、可维护性、可扩展性和稳定性。在前端开发中&#xff0c;提升代码质量可以帮助我们减少错误、提高开发效率、降低维护成本&#xff0c;甚至可以提高用户体验。 在必要的地方加注释 良好的注释可以帮助开发人员理…

使用RKDevTool将update.img完整镜像进行解包,得到单独分区的镜像

(1)使用开发工具高级功能的解包 导入xx.img,然后点击解包(2)在Output/Android/Image得到想要的image

zotero通过DOI快速导入文献

之前我经常采用两种方式导入文献&#xff1a; &#xff08;1&#xff09;下载PDF&#xff0c;然后拖入zotero 这种方法比较费时间&#xff0c;有些文献无法下载pdf &#xff08;2&#xff09;通过google scholar检索文献&#xff0c;然后点击引用——EndNote&#xff0c;chorme…

HCQ1-1300-D故障笔记

常用查错网址&#xff1a; SMC_ERROR (ENUM) 删除 Web

socket套接字——TCP协议

目录 一、TCP协议相关函数 1.socket、bind函数 2.listen函数 3.accept函数 4.connect函数 二、实现TCP通信 1.服务端实现 &#xff08;1&#xff09;服务端类 &#xff08;2&#xff09;日志小组件 &#xff08;3&#xff09;初始化服务端 &#xff08;4&#xff09…

etcd的安装和使用

安装及启动 在Mac上&#xff0c;推荐使用brew安装 brew install etcd 可以使用etcd启动服务&#xff0c;但更推荐使用 brew services 来管理使用brew安装的应用~ # 启动某个应用&#xff0c;这里用 etcd 做演示brew services start etcd# 停止某个应用brew services stop etcd#…

Hive的分区和分桶

目录 ​编辑 一、Hive分区 1.1 分区产生的背景 1.2 动态分区 1.2.1 hive的动态分区介绍 1.2.2 动态分区配置 1.2.2.1 动态分区开启 1.2.2.2 动态分区模式 1.2.2.3 一个mr节点上&#xff0c;设置动态分区的最大数量 1.2.2.4 所有mr节点上&#xff0c;设置所有动态分区…

linux安装redis超级详细教程

redis源码安装 安装gcc redis是C语言编写的&#xff0c;所以我们需要先在Linux上安装和升级&#xff0c;C语言的编译环境。 #安装gcc yum install -y gcc-c autoconf automake#centos7 默认的 gcc 默认是4.8.5,版本小于 5.3 无法编译,需要先安装gcc新版才能编译 gcc -v#升级…

rv1126-rv1109-环境搭建-全部编译的方法

主要参考:Rockchip_Developer_Guide_Linux_Software_CN.pdf / SDK-Rockchip_RV1126_RV1109_Quick_Start_Linux_CN.pdf 找对文档事半功倍!为什么这么说,因为没找对绕了路!别笑! //解压源码,基础略过 tar xvf rv1126_rv1109_linux_v3.0.2_20230724.tgz -C rv1126_rv1109 cd rv1…

【Axure高保真原型】动态控制不透明度

今天和大家分享动态控制不透明度的原型模板&#xff0c;我们可以滑块左右拖动或者点击滑条的某个位置&#xff0c;从而控制图片上方遮罩的不透明度……具体效果可以打开下方原型地址体验或者点击下方视频观看 【原型效果】 【Axure高保真原型】动态控制不透明度 【原型预览及下…

No thread-bound request found 错误以及解决方案

异常信息&#xff1a; cause: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually o…

一起学数据结构(7)——树及二叉树的基本概念及存储

前面的关于数据结构的文章中&#xff0c;介绍了顺序表&#xff0c;链表&#xff0c;栈&#xff0c;队列等数据结构。对于以上数据结构&#xff0c;均是一对一的关系。本篇文章将对于一对多的数据结构——树进行解析。 目录 1. 树的定义及基本概念&#xff1a; 1.1 树的定义&a…

结合el-tooltip,实现内容过长省略,移上显示全部

在系统中&#xff0c;内容过长需要省略&#xff0c;鼠标移上显示全部&#xff0c;这个是常用的功能&#xff0c;也有很多方案解决这种。 单行内容超出处理 常用的css方案&#xff1a; .ellipsis {overflow: hidden;white-space: nowrap;text-overflow: ellipsis; } 该样式在…

基于Android系统英语学习助手APP设计开发

一、 设计思路 1.1设计目标 1.2设计思路 1.3设计内容 1.3.1界面设计 1.3.2功能模块设计 1.3.3功能流程图 1.3.4数据库设计&#xff08;如果没有数据库这部分删除&#xff09; 1.4工具设备要求 1.5技术方案 二、设计过程与说明 2.1技术路线 2.2实现方案 2.3实现原理…

C#复习:面向对象基本概念

C#复习&#xff1a;面向对象基本概念 前言什么是面向对象类&#xff0c;名称空间的介绍 如何导入类库DLL引用(黑盒引用)项目引用(白盒引用)NuGet介绍 依赖关系C#的分装(个人理解) 前言 关于我C#的博客是根据刘铁猛老师的C#入门课程为基础写的&#xff0c;可以配合刘铁猛老师的…

.bat批处理命令处理文件

批处理命令处理文件找到上级目录&#xff0c;并删除文件与文件夹 参考资料&#xff1a; [BAT] 如何获取bat的上一级目录、上两级目录..._bat 上层目录_Risun_Lee的博客-CSDN博客echo offset currPath%~dp0set parentPathset parentparentPath:beginfor /f "tokens1,* de…

solidworks导出文本能打开的stl文件

几种以文本格式&#xff08;ASCII&#xff09;导出stl的设置 1.solidworks导出时需要在选项里设置导出格式为ASCII&#xff0c;当选择以二进制格式导出时&#xff0c;打开会乱码&#xff1b; 2.CAD直接导出的是以二进制形式导出的&#xff0c;导出后也无法使用文本打开&#xf…

NVIDIA DALI学习:数据加载

DALI的工作流&#xff0c; 如下图&#xff1a; 读取数据图像解码和变换&#xff0c;可以放到GPU上进行&#xff0c;也是加速的关键生成处理好的数据&#xff0c; 导出给计算引擎 测试用例 import ctypesimport numpy as np import nvidia.dali.fn as fn import nvidia.dali…