Преглед изворни кода

Merge branch 'dev' of http://110.41.163.243:9980/kd-aiot/kd-aiot-frontend into dengfei

695593266@qq.com пре 3 месеци
родитељ
комит
e3dd92c3b4

+ 37 - 0
src/api/rulesManagement/paymentTerms/index.js

@@ -0,0 +1,37 @@
+import request from '@/utils/request';
+
+// 获取付款条件列表
+export function getTableList(data) {
+  return request({
+    url: '/api/paymentTerms/list',
+    method: 'post',
+    data
+  });
+}
+
+// 新增付款条件
+export function addPaymentTerms(data) {
+  return request({
+    url: '/api/paymentTerms',
+    method: 'post',
+    data
+  });
+}
+
+// 修改付款条件
+export function updatePaymentTerms(data) {
+  return request({
+    url: '/api/paymentTerms',
+    method: 'put',
+    data
+  });
+}
+
+// 删除付款条件
+export function deleteInformation(data) {
+  return request({
+    url: '/api/paymentTerms',
+    method: 'delete',
+    data
+  });
+}

+ 37 - 0
src/api/rulesManagement/receiveTerms/index.js

@@ -0,0 +1,37 @@
+import request from '@/utils/request';
+
+// 获取收款条件列表
+export function getTableList(data) {
+  return request({
+    url: '/api/receiveTerms/list',
+    method: 'post',
+    data
+  });
+}
+
+// 新增收款条件
+export function addReceiveTerms(data) {
+  return request({
+    url: '/api/receiveTerms',
+    method: 'post',
+    data
+  });
+}
+
+// 修改收款条件
+export function updateReceiveTerms(data) {
+  return request({
+    url: '/api/receiveTerms',
+    method: 'put',
+    data
+  });
+}
+
+// 删除收款条件
+export function deleteInformation(data) {
+  return request({
+    url: '/api/receiveTerms',
+    method: 'delete',
+    data
+  });
+}

+ 10 - 3
src/api/system/organization/index.js

@@ -173,7 +173,6 @@ export async function getCurrentUserAuthorityDeptAPI() {
   return Promise.reject(new Error(res.data.message));
 }
 
-
 /**
  * 组织结构导出
  * @param
@@ -196,7 +195,7 @@ export async function employeePush(data) {
     return res.data.data;
   }
   return Promise.reject(new Error(res.data.message));
-}  
+}
 
 // 通过部门数组获取人员列表
 export async function getUserByGroupIds(data) {
@@ -205,4 +204,12 @@ export async function getUserByGroupIds(data) {
     return res.data.data;
   }
   return Promise.reject(new Error(res.data.message));
-}
+}
+// 创建个人文档区
+export async function createPersonal(data) {
+  const res = await request.post('/fm/directory/createPersonal/'+data, {});
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 75 - 0
src/api/system/‌doorSecurity‌/index.js

@@ -0,0 +1,75 @@
+import request from '@/utils/request';
+
+/**
+ * 绑定列表
+ * @param params 查询条件
+ */
+export async function listDoorUsers(params) {
+  const res = await request.get('/mms/acs/bind/list', {
+    params
+  });
+  if (res.data.code == 0 && res.data.data) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}  
+
+/**
+ * 设备台账
+ * @param params 菜单信息
+ */
+export async function listDevice(params) {
+  const res = await request.post(`/mms/access/device/list`, params);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 绑定
+ * @param params 菜单信息
+ */
+export async function bindDevice(params) {
+  const res = await request.post(`/mms/acs/bind/bind`, params);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 绑定
+ * @param params 菜单信息
+ */
+export async function editBind(params) {
+  const res = await request.post(`/mms/acs/bind/edit`, params);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+} 
+
+/**
+ * 同步
+ * @param params 菜单信息
+ */
+export async function syncDevice(id) {
+  const res = await request.post(`/mms/acs/bind/sync-pull/${id}`);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 同步
+ * @param params 菜单信息
+ */
+export async function unbindDevice(id) {
+  const res = await request.post(`/mms/acs/bind/unbind/${id}`);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 63 - 1
src/enum/dict.js

@@ -88,7 +88,8 @@ export default {
   实验规则类型: 'experiment_sheet',
   实验模板样式: 'experiment_template_style',
   表计类型: 'meter_type',
-  印章类型: 'main_seal_type'
+  印章类型: 'main_seal_type',
+  支付类型: 'payment_type',
 };
 
 export const numberList = [
@@ -249,6 +250,67 @@ export const produceTypeList = [
   }
 ];
 
+// 付款日计算日期
+export const calcPayDateTypeOp = [
+  {
+    label: '订单日期',
+    value: 1
+  },
+  {
+    label: '入库日期',
+    value: 2
+  },
+  {
+    label: '收票日期',
+    value: 3
+  },
+  {
+    label: '对账单日期',
+    value: 4
+  },
+  {
+    label: '应付单日期',
+    value: 5
+  }
+];
+
+// 收款日计算日期
+export const calcReceiveDateTypeOp = [
+  {
+    label: '订单日期',
+    value: 1
+  },
+  {
+    label: '出库日期',
+    value: 2
+  },
+  {
+    label: '应收单日期',
+    value: 3
+  },
+  {
+    label: '开票日期',
+    value: 4
+  },
+  {
+    label: '对账单日期',
+    value: 5
+  }
+]
+
+// 收/付款日确定方式         
+export const payConfirmTypeOp = [
+  {
+    label: '交易日',
+    value: 1
+  },
+  {
+    label: 'X天后',
+    value: 2
+  }
+]
+
+
 //持证类型
 export const holderTypeOptions = [
   {

+ 48 - 4
src/views/enterpriseModel/dept/components/staffSelection.vue

@@ -59,7 +59,33 @@
                       <div>{{ row.jobNumber }}</div>
                     </template>
                   </el-table-column>
-                  <el-table-column width="80" label="操作">
+                  <!-- <el-table-column width="80" label="操作">
+                    <template slot-scope="{ row }">
+                      <el-button
+                        size="mini"
+                        type="primary"
+                        @click="choiceAsset(row)"
+                        :disabled="row.disabled"
+                        icon="el-icon-arrow-right"
+                        circle
+                      >
+                      </el-button>
+                    </template>
+                  </el-table-column> -->
+                  <el-table-column width="180" label="操作" align="right">
+                    <template slot="header" slot-scope="scope">
+                      <div style="display: flex">
+
+                        <el-input v-model="userName" placeholder="输入姓名查询" clearable
+                                  @change="changeUserName"></el-input>
+                        <div
+                          v-if="staffList.length !== 0 && isMore"
+                          class="zw-page-list-more"
+                        >
+                          <el-button type="text" @click="getMore()">更多<i class="el-icon-caret-bottom"></i></el-button>
+                        </div>
+                      </div>
+                    </template>
                     <template slot-scope="{ row }">
                       <el-button
                         size="mini"
@@ -72,15 +98,18 @@
                       </el-button>
                     </template>
                   </el-table-column>
+                  <el-table-column width="80" label="操作">
+
+                  </el-table-column>
                 </el-table>
-                <div
+                <!-- <div
                   v-if="staffList.length !== 0 && isMore"
                   class="zw-page-list-more"
                 >
                   <el-link @click="getMore()" type="primary"
                     >更多<i class="el-icon-caret-bottom"></i>
                   </el-link>
-                </div>
+                </div> -->
               </el-container>
             </div>
           </el-card>
@@ -146,6 +175,7 @@
         treeList: [],
         staffList: [],
         selectStafflist: [], //已选员工
+        userName: '',
         defaultProps: {
           children: 'children',
           label: 'name',
@@ -159,6 +189,19 @@
     },
     created() {},
     methods: {
+      changeUserName() {
+        this.staffList = [];
+        this.pageNum = 1;
+        // this.form.groupId = this.currentData.id;
+        let params = {
+          pageNum: 1,
+          size: this.size,
+          groupId: this.form.groupId,
+          name: this.userName
+        };
+   
+        this.getStaffList(params);
+      },
       open(selectedList) {
         this.dialogVisible = true;
         this.pageNum = 1;
@@ -226,7 +269,8 @@
         let params = {
           pageNum: this.pageNum,
           size: this.size,
-          groupId: this.form.groupId
+          groupId: this.form.groupId,
+          name: this.userName
         };
         this.getStaffList(params);
       },

+ 378 - 0
src/views/rulesManagement/paymentTerms/components/addDialog.vue

@@ -0,0 +1,378 @@
+<!-- 新增/编辑弹窗 -->
+<template>
+  <ele-modal
+    width="700px"
+    :visible="visible"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    :title="isDetail ? '付款条件详情' : (isUpdate ? '修改付款条件' : '新增付款条件')"
+    @update:visible="updateVisible"
+  >
+    <el-form
+      ref="form"
+      :model="form"
+      :rules="rules"
+      label-width="140px"
+    >
+      <!-- 付款条件编码 -->
+      <el-form-item label="付款条件编码:" prop="code">
+        <el-input
+          v-model="form.code"
+          placeholder="FKTJ+年月日+3位数字"
+          :disabled="true"
+        />
+      </el-form-item>
+
+      <!-- 付款条件名称 -->
+      <el-form-item label="付款条件名称:" prop="name">
+        <el-input
+          clearable
+          v-model="form.name"
+          placeholder="请输入付款条件名称"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+
+      <!-- 付款日计算日期 -->
+      <el-form-item label="付款日计算日期:" prop="calcDateType">
+        <el-select
+          v-model="form.calcDateType"
+          placeholder="请选择"
+          style="width: 100%"
+          :disabled="isDetail"
+        >
+          <el-option v-for="item in calcPayDateTypeOp" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 付款日确定方式 -->
+      <el-form-item label="付款日确定方式:" prop="confirmType">
+        <el-select
+          v-model="form.confirmType"
+          placeholder="请选择"
+          style="width: 100%"
+          :disabled="isDetail"
+          @change="handleConfirmTypeChange"
+        >
+          <el-option v-for="item in payConfirmTypeOp" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 月数(X天后显示) -->
+      <el-form-item label="月数:" v-if="form.confirmType === 2">
+        <el-input-number
+          v-model="form.months"
+          :min="0"
+          :precision="0"
+          controls-position="right"
+          style="width: 100%"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+
+      <!-- 天数(X天后显示) -->
+      <el-form-item label="天数:" v-if="form.confirmType === 2">
+        <el-input-number
+          v-model="form.days"
+          :min="0"
+          :precision="0"
+          controls-position="right"
+          style="width: 100%"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+
+      <!-- 支付方式列表 -->
+      <el-form-item
+        v-for="(item, index) in form.paymentList"
+        :key="item.id"
+        :label="index === 0 ? '支付方式:' : ''"
+        :required="index === 0"
+        class="payment-method-item"
+      >
+        <div class="payment-method-row">
+          <el-input-number
+            v-model="item.ratio"
+            :min="0"
+            :max="100"
+            :precision="0"
+            controls-position="right"
+            class="payment-input"
+            placeholder="比例"
+            :disabled="isDetail"
+          />
+          <span class="payment-unit">%</span>
+          <el-input-number
+            v-model="item.months"
+            :min="0"
+            :precision="0"
+            controls-position="right"
+            class="payment-input"
+            placeholder="月数"
+            :disabled="isDetail"
+          />
+          <span class="payment-unit">月</span>
+          <DictSelection
+            v-model="item.type"
+            dictName="支付类型"
+            placeholder="请选择"
+            class="payment-select"
+            :disabled="isDetail"
+          />
+          <el-button
+            v-if="!isDetail && form.paymentList.length > 1 && index !== 0"
+            type="text"
+            icon="el-icon-remove-outline"
+            class="remove-payment-btn"
+            @click="removePaymentRow(index)"
+          />
+          <el-button
+            v-if="!isDetail && index === form.paymentList.length - 1"
+            type="text"
+            icon="el-icon-circle-plus-outline"
+            class="add-payment-btn"
+            @click="addPaymentRow"
+          />
+        </div>
+      </el-form-item>
+
+      <!-- 备注 -->
+      <el-form-item label="备注:" prop="remark">
+        <el-input
+          type="textarea"
+          :rows="3"
+          v-model="form.remark"
+          placeholder="请输入"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+    </el-form>
+
+    <template v-slot:footer>
+      <template v-if="isDetail">
+        <el-button @click="updateVisible(false)">关闭</el-button>
+      </template>
+      <template v-else>
+        <el-button type="primary" :loading="loading" @click="save">
+          确定
+        </el-button>
+        <el-button @click="updateVisible(false)">取消</el-button>
+      </template>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  import { addPaymentTerms, updatePaymentTerms } from '@/api/rulesManagement/paymentTerms';
+  import { calcPayDateTypeOp, payConfirmTypeOp } from '@/enum/dict';
+
+  let paymentId = 0;
+
+  export default {
+    data() {
+      return {
+        visible: false,
+        loading: false,
+        isUpdate: false,
+        isDetail: false,
+        calcPayDateTypeOp,
+        payConfirmTypeOp,
+        form: {
+          id: null,
+          code: '',
+          name: '',
+          calcDateType: null,
+          confirmType: null,
+          months: 0,
+          days: 0,
+          paymentList: [],
+          remark: ''
+        },
+        rules: {
+          code: [{ required: true, message: '请输入付款条件编码', trigger: 'blur' }],
+          name: [{ required: true, message: '请输入付款条件名称', trigger: 'blur' }],
+          calcDateType: [{ required: true, message: '请选择付款日计算日期', trigger: 'change' }],
+          confirmType: [{ required: true, message: '请选择付款日确定方式', trigger: 'change' }]
+        }
+      };
+    },
+    methods: {
+      // 生成编码 FKTJ+年月日+3位数字
+      generateCode() {
+        const now = new Date();
+        const year = now.getFullYear();
+        const month = String(now.getMonth() + 1).padStart(2, '0');
+        const day = String(now.getDate()).padStart(2, '0');
+        const random = String(Math.floor(Math.random() * 900) + 100);
+        this.form.code = `FKTJ${year}${month}${day}${random}`;
+      },
+
+      open(type, row) {
+        this.visible = true;
+        this.isUpdate = type === 'edit';
+        this.isDetail = type === 'detail';
+        if ((this.isUpdate || this.isDetail) && row) {
+          this.form = {
+            ...row,
+            paymentList: this.parsePaymentMethod(row.paymentMethod)
+          };
+          if (!this.form.paymentList || this.form.paymentList.length === 0) {
+            this.form.paymentList = [this.createEmptyPayment()];
+          }
+        } else {
+          this.resetForm();
+          this.generateCode();
+        }
+        this.$nextTick(() => {
+          this.$refs.form && this.$refs.form.clearValidate();
+        });
+      },
+
+      resetForm() {
+        this.form = {
+          id: null,
+          code: '',
+          name: '',
+          calcDateType: 1,        // 默认:订单日期
+          confirmType: 1,         // 默认:交易日(隐藏月数、天数)
+          months: 0,
+          days: 0,
+          paymentList: [this.createEmptyPayment()], // 默认:100% 0月 现金
+          remark: ''
+        };
+      },
+
+      createEmptyPayment() {
+        return {
+          id: ++paymentId,
+          ratio: 100,
+          months: 0,
+          type: '现金'
+        };
+      },
+
+      // 解析支付方式字符串为数组
+      parsePaymentMethod(methodStr) {
+        if (!methodStr) return [this.createEmptyPayment()];
+        const parts = methodStr.split(',');
+        return parts.map(part => {
+          const match = part.trim().match(/(\d+)%\s*(\d+)月\s*(.+)/);
+          if (match) {
+            return {
+              id: ++paymentId,
+              ratio: parseInt(match[1]),
+              months: parseInt(match[2]),
+              type: match[3]
+            };
+          }
+          return null;
+        }).filter(Boolean);
+      },
+
+      // 付款日确定方式变化
+      handleConfirmTypeChange() {
+        if (this.form.confirmType === 1) {
+          this.form.months = 0;
+          this.form.days = 0;
+        }
+      },
+
+      // 添加支付方式行
+      addPaymentRow() {
+        this.form.paymentList.push(this.createEmptyPayment());
+      },
+
+      // 移除支付方式行
+      removePaymentRow(index) {
+        this.form.paymentList.splice(index, 1);
+      },
+
+      // 构建支付方式字符串
+      buildPaymentMethod() {
+        return this.form.paymentList
+          .map(item => `${item.ratio}% ${item.months}月 ${item.type}`)
+          .join(',');
+      },
+
+      // 构建确认方式描述
+      buildConfirmDesc() {
+        if (this.form.confirmType === 1) {
+          return '交易日';
+        }
+        const parts = [];
+        if (this.form.months > 0) parts.push(`月数:${this.form.months}`);
+        if (this.form.days > 0) parts.push(`天数:${this.form.days}`);
+        if (parts.length === 0) return '0月0天即交易日';
+        return parts.join(',');
+      },
+
+      save() {
+        this.$refs.form.validate((valid) => {
+          if (!valid) return;
+
+          // 校验支付方式比例总和
+          const totalRatio = this.form.paymentList.reduce((sum, item) => sum + item.ratio, 0);
+          if (totalRatio !== 100) {
+            this.$message.warning('支付比例总和必须等于100%');
+            return;
+          }
+
+          this.loading = true;
+
+          const data = {
+            ...this.form,
+            paymentMethod: this.buildPaymentMethod(),
+            confirmDesc: this.buildConfirmDesc()
+          };
+          delete data.paymentList;
+
+          const saveOrUpdate = this.isUpdate ? updatePaymentTerms : addPaymentTerms;
+          saveOrUpdate(data)
+            .then(() => {
+              this.loading = false;
+              this.$message.success(this.isUpdate ? '修改成功' : '新增成功');
+              this.updateVisible(false);
+              this.$emit('done');
+            })
+            .catch(() => {
+              this.loading = false;
+            });
+        });
+      },
+
+      updateVisible(value) {
+        this.visible = value;
+        if (!value) {
+          this.resetForm();
+        }
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  .payment-method-row {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+  .payment-input {
+    width: 100px;
+  }
+  .payment-unit {
+    color: #606266;
+    font-size: 14px;
+  }
+  .payment-select {
+    width: 120px!important;
+  }
+  .add-payment-btn,
+  .remove-payment-btn {
+    font-size: 18px;
+    padding: 0;
+  }
+  .remove-payment-btn {
+    color: #f56c6c;
+  }
+</style>

+ 55 - 0
src/views/rulesManagement/paymentTerms/components/searchForm.vue

@@ -0,0 +1,55 @@
+<!-- 搜索表单 -->
+<template>
+  <seekPage :seekList="seekList" :formLength="3" @search="search"></seekPage>
+</template>
+
+<script>
+  export default {
+    data() {
+      return {};
+    },
+    computed: {
+      seekList() {
+        return [
+          {
+            label: '关键词:',
+            value: 'searchName',
+            type: 'input',
+            placeholder: '编码、名称、型号、规格'
+          },
+          {
+            label: '下拉检索:',
+            value: 'searchType',
+            type: 'select',
+            placeholder: '请选择',
+            planList: [
+              { value: 1, label: '选项一' },
+              { value: 2, label: '选项二' },
+              { value: 3, label: '选项三' }
+            ]
+          },
+          {
+            label: '关键词:',
+            value: 'searchName2',
+            type: 'input',
+            placeholder: '编码、名称、型号、规格'
+          },
+          {
+            label: '创建时间:',
+            value: 'createTime',
+            type: 'date',
+            dateType: 'daterange',
+            placeholder: '',
+            width: 380,
+            valueAr: ['createTimeStart', 'createTimeEnd']
+          }
+        ];
+      }
+    },
+    methods: {
+      search(e) {
+        this.$emit('search', { ...e });
+      }
+    }
+  };
+</script>

+ 227 - 0
src/views/rulesManagement/paymentTerms/index.vue

@@ -0,0 +1,227 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never" v-loading="loading">
+      <div class="ele-border-lighter form-content" v-loading="loading">
+        <search-form @search="reload"> </search-form>
+
+        <!-- 数据表格 -->
+        <ele-pro-table
+          ref="table"
+          :columns="columns"
+          :datasource="datasource"
+          height="calc(100vh - 375px)"
+          full-height="calc(100vh - 116px)"
+          tool-class="ele-toolbar-form"
+          :selection.sync="selection"
+          :page-size="20"
+          @columns-change="handleColumnChange"
+          :cache-key="cacheKeyUrl"
+        >
+          <!-- 表头工具栏 -->
+          <template v-slot:toolbar>
+            <el-button
+              size="small"
+              type="primary"
+              icon="el-icon-plus"
+              class="ele-btn-icon"
+              @click="openEdit('add', {})"
+            >
+              新增
+            </el-button>
+          </template>
+
+          <!-- 操作列 -->
+          <template v-slot:action="{ row }">
+            <el-link
+              type="primary"
+              :underline="false"
+              icon="el-icon-view"
+              @click="openDetail(row)"
+            >
+              详情
+            </el-link>
+            <el-link
+              type="primary"
+              :underline="false"
+              icon="el-icon-edit"
+              @click="openEdit('edit', row)"
+            >
+              修改
+            </el-link>
+            <el-popconfirm
+              class="ele-action"
+              title="确定要删除此信息吗?"
+              @confirm="remove([row.id])"
+            >
+              <template v-slot:reference>
+                <el-link type="danger" :underline="false" icon="el-icon-delete">
+                  删除
+                </el-link>
+              </template>
+            </el-popconfirm>
+          </template>
+        </ele-pro-table>
+      </div>
+    </el-card>
+
+    <add-dialog ref="addDialogRef" @done="reload"></add-dialog>
+  </div>
+</template>
+
+<script>
+  import searchForm from './components/searchForm.vue';
+  import addDialog from './components/addDialog.vue';
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  import {
+    getTableList,
+    deleteInformation
+  } from '@/api/rulesManagement/paymentTerms';
+
+  export default {
+    mixins: [tabMixins],
+    components: {
+      searchForm,
+      addDialog
+    },
+    data() {
+      return {
+        selection: [],
+        loading: false,
+        columns: [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'code',
+            label: '编码',
+            align: 'center',
+            sortable: true,
+            showOverflowTooltip: true,
+            minWidth: 160
+          },
+          {
+            prop: 'name',
+            label: '付款条件名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160
+          },
+          {
+            prop: 'calcDateType',
+            label: '付款日计算日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160,
+            formatter: (row) => {
+              const map = {
+                1: '订单日期',
+                2: '入库日期',
+                3: '收票日期',
+                4: '对账单日期',
+                5: '应付单日期'
+              };
+              return map[row.calcDateType] || '';
+            }
+          },
+          {
+            prop: 'paymentMethod',
+            label: '支付方式',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 180
+          },
+          {
+            prop: 'confirmType',
+            label: '付款日确认方式',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 140,
+            formatter: (row) => {
+              const map = {
+                1: '交易日',
+                2: 'X天后'
+              };
+              return map[row.confirmType] || '';
+            }
+          },
+          {
+            prop: 'confirmDesc',
+            label: '付款日确认方式描述',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 180
+          },
+          {
+            prop: 'createUserName',
+            label: '创建人',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 170,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            showOverflowTooltip: true,
+            fixed: 'right'
+          }
+        ],
+        cacheKeyUrl: 'eos-paymentTerms-list'
+      };
+    },
+    methods: {
+      /* 表格数据源 */
+      datasource({ page, limit, where }) {
+        return getTableList({
+          pageNum: page,
+          size: limit,
+          ...where
+        });
+      },
+
+      /* 刷新表格 */
+      reload(where) {
+        this.$refs.table.reload({ page: 1, where });
+      },
+
+      // 新增编辑
+      openEdit(type, row) {
+        this.$refs.addDialogRef.open(type, row);
+      },
+
+      // 查看详情
+      openDetail(row) {
+        this.$refs.addDialogRef.open('detail', row);
+      },
+
+      // 删除
+      remove(delData) {
+        deleteInformation(delData).then(() => {
+          this.$message.success('删除成功!');
+          this.reload();
+        });
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  :deep(.el-link--inner) {
+    margin-left: 0px !important;
+  }
+</style>

+ 378 - 0
src/views/rulesManagement/receiveTerms/components/addDialog.vue

@@ -0,0 +1,378 @@
+<!-- 新增/编辑弹窗 -->
+<template>
+  <ele-modal
+    width="700px"
+    :visible="visible"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    :title="isDetail ? '收款条件详情' : (isUpdate ? '修改收款条件' : '新增收款条件')"
+    @update:visible="updateVisible"
+  >
+    <el-form
+      ref="form"
+      :model="form"
+      :rules="rules"
+      label-width="140px"
+    >
+      <!-- 收款条件编码 -->
+      <el-form-item label="收款条件编码:" prop="code">
+        <el-input
+          v-model="form.code"
+          placeholder="SKTJ+年月日+3位数字"
+          :disabled="true"
+        />
+      </el-form-item>
+
+      <!-- 收款条件名称 -->
+      <el-form-item label="收款条件名称:" prop="name">
+        <el-input
+          clearable
+          v-model="form.name"
+          placeholder="请输入收款条件名称"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+
+      <!-- 收款日计算日期 -->
+      <el-form-item label="收款日计算日期:" prop="calcDateType">
+        <el-select
+          v-model="form.calcDateType"
+          placeholder="请选择"
+          style="width: 100%"
+          :disabled="isDetail"
+        >
+          <el-option v-for="item in calcReceiveDateTypeOp" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 收款日确定方式 -->
+      <el-form-item label="收款日确定方式:" prop="confirmType">
+        <el-select
+          v-model="form.confirmType"
+          placeholder="请选择"
+          style="width: 100%"
+          :disabled="isDetail"
+          @change="handleConfirmTypeChange"
+        >
+          <el-option v-for="item in payConfirmTypeOp" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 月数(X天后显示) -->
+      <el-form-item label="月数:" v-if="form.confirmType === 2">
+        <el-input-number
+          v-model="form.months"
+          :min="0"
+          :precision="0"
+          controls-position="right"
+          style="width: 100%"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+
+      <!-- 天数(X天后显示) -->
+      <el-form-item label="天数:" v-if="form.confirmType === 2">
+        <el-input-number
+          v-model="form.days"
+          :min="0"
+          :precision="0"
+          controls-position="right"
+          style="width: 100%"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+
+      <!-- 支付方式列表 -->
+      <el-form-item
+        v-for="(item, index) in form.paymentList"
+        :key="item.id"
+        :label="index === 0 ? '支付方式:' : ''"
+        :required="index === 0"
+        class="payment-method-item"
+      >
+        <div class="payment-method-row">
+          <el-input-number
+            v-model="item.ratio"
+            :min="0"
+            :max="100"
+            :precision="0"
+            controls-position="right"
+            class="payment-input"
+            placeholder="比例"
+            :disabled="isDetail"
+          />
+          <span class="payment-unit">%</span>
+          <el-input-number
+            v-model="item.months"
+            :min="0"
+            :precision="0"
+            controls-position="right"
+            class="payment-input"
+            placeholder="月数"
+            :disabled="isDetail"
+          />
+          <span class="payment-unit">月</span>
+          <DictSelection
+            v-model="item.type"
+            dictName="支付类型"
+            placeholder="请选择"
+            class="payment-select"
+            :disabled="isDetail"
+          />
+          <el-button
+            v-if="!isDetail && index === form.paymentList.length - 1"
+            type="text"
+            icon="el-icon-circle-plus-outline"
+            class="add-payment-btn"
+            @click="addPaymentRow"
+          />
+          <el-button
+            v-if="!isDetail && form.paymentList.length > 1 && index !== 0"
+            type="text"
+            icon="el-icon-remove-outline"
+            class="remove-payment-btn"
+            @click="removePaymentRow(index)"
+          />
+        </div>
+      </el-form-item>
+
+      <!-- 备注 -->
+      <el-form-item label="备注:" prop="remark">
+        <el-input
+          type="textarea"
+          :rows="3"
+          v-model="form.remark"
+          placeholder="请输入"
+          :disabled="isDetail"
+        />
+      </el-form-item>
+    </el-form>
+
+    <template v-slot:footer>
+      <template v-if="isDetail">
+        <el-button @click="updateVisible(false)">关闭</el-button>
+      </template>
+      <template v-else>
+        <el-button type="primary" :loading="loading" @click="save">
+          确定
+        </el-button>
+        <el-button @click="updateVisible(false)">取消</el-button>
+      </template>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  import { addReceiveTerms, updateReceiveTerms } from '@/api/rulesManagement/receiveTerms';
+  import { calcReceiveDateTypeOp, payConfirmTypeOp } from '@/enum/dict';
+
+  let paymentId = 0;
+
+  export default {
+    data() {
+      return {
+        visible: false,
+        loading: false,
+        isUpdate: false,
+        isDetail: false,
+        calcReceiveDateTypeOp,
+        payConfirmTypeOp,
+        form: {
+          id: null,
+          code: '',
+          name: '',
+          calcDateType: null,
+          confirmType: null,
+          months: 0,
+          days: 0,
+          paymentList: [],
+          remark: ''
+        },
+        rules: {
+          code: [{ required: true, message: '请输入收款条件编码', trigger: 'blur' }],
+          name: [{ required: true, message: '请输入收款条件名称', trigger: 'blur' }],
+          calcDateType: [{ required: true, message: '请选择收款日计算日期', trigger: 'change' }],
+          confirmType: [{ required: true, message: '请选择收款日确定方式', trigger: 'change' }]
+        }
+      };
+    },
+    methods: {
+      // 生成编码 SKTJ+年月日+3位数字
+      generateCode() {
+        const now = new Date();
+        const year = now.getFullYear();
+        const month = String(now.getMonth() + 1).padStart(2, '0');
+        const day = String(now.getDate()).padStart(2, '0');
+        const random = String(Math.floor(Math.random() * 900) + 100);
+        this.form.code = `SKTJ${year}${month}${day}${random}`;
+      },
+
+      open(type, row) {
+        this.visible = true;
+        this.isUpdate = type === 'edit';
+        this.isDetail = type === 'detail';
+        if ((this.isUpdate || this.isDetail) && row) {
+          this.form = {
+            ...row,
+            paymentList: this.parsePaymentMethod(row.paymentMethod)
+          };
+          if (!this.form.paymentList || this.form.paymentList.length === 0) {
+            this.form.paymentList = [this.createEmptyPayment()];
+          }
+        } else {
+          this.resetForm();
+          this.generateCode();
+        }
+        this.$nextTick(() => {
+          this.$refs.form && this.$refs.form.clearValidate();
+        });
+      },
+
+      resetForm() {
+        this.form = {
+          id: null,
+          code: '',
+          name: '',
+          calcDateType: 1,        // 默认:订单日期
+          confirmType: 1,         // 默认:交易日(隐藏月数、天数)
+          months: 0,
+          days: 0,
+          paymentList: [this.createEmptyPayment()], // 默认:100% 0月 现金
+          remark: ''
+        };
+      },
+
+      createEmptyPayment() {
+        return {
+          id: ++paymentId,
+          ratio: 100,
+          months: 0,
+          type: '现金'
+        };
+      },
+
+      // 解析支付方式字符串为数组
+      parsePaymentMethod(methodStr) {
+        if (!methodStr) return [this.createEmptyPayment()];
+        const parts = methodStr.split(',');
+        return parts.map(part => {
+          const match = part.trim().match(/(\d+)%\s*(\d+)月\s*(.+)/);
+          if (match) {
+            return {
+              id: ++paymentId,
+              ratio: parseInt(match[1]),
+              months: parseInt(match[2]),
+              type: match[3]
+            };
+          }
+          return null;
+        }).filter(Boolean);
+      },
+
+      // 收款日确定方式变化
+      handleConfirmTypeChange() {
+        if (this.form.confirmType === 1) {
+          this.form.months = 0;
+          this.form.days = 0;
+        }
+      },
+
+      // 添加支付方式行
+      addPaymentRow() {
+        this.form.paymentList.push(this.createEmptyPayment());
+      },
+
+      // 移除支付方式行
+      removePaymentRow(index) {
+        this.form.paymentList.splice(index, 1);
+      },
+
+      // 构建支付方式字符串
+      buildPaymentMethod() {
+        return this.form.paymentList
+          .map(item => `${item.ratio}% ${item.months}月 ${item.type}`)
+          .join(',');
+      },
+
+      // 构建确认方式描述
+      buildConfirmDesc() {
+        if (this.form.confirmType === 1) {
+          return '交易日';
+        }
+        const parts = [];
+        if (this.form.months > 0) parts.push(`月数:${this.form.months}`);
+        if (this.form.days > 0) parts.push(`天数:${this.form.days}`);
+        if (parts.length === 0) return '0月0天即交易日';
+        return parts.join(',');
+      },
+
+      save() {
+        this.$refs.form.validate((valid) => {
+          if (!valid) return;
+
+          // 校验支付方式比例总和
+          const totalRatio = this.form.paymentList.reduce((sum, item) => sum + item.ratio, 0);
+          if (totalRatio !== 100) {
+            this.$message.warning('支付比例总和必须等于100%');
+            return;
+          }
+
+          this.loading = true;
+
+          const data = {
+            ...this.form,
+            paymentMethod: this.buildPaymentMethod(),
+            confirmDesc: this.buildConfirmDesc()
+          };
+          delete data.paymentList;
+
+          const saveOrUpdate = this.isUpdate ? updateReceiveTerms : addReceiveTerms;
+          saveOrUpdate(data)
+            .then(() => {
+              this.loading = false;
+              this.$message.success(this.isUpdate ? '修改成功' : '新增成功');
+              this.updateVisible(false);
+              this.$emit('done');
+            })
+            .catch(() => {
+              this.loading = false;
+            });
+        });
+      },
+
+      updateVisible(value) {
+        this.visible = value;
+        if (!value) {
+          this.resetForm();
+        }
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  .payment-method-row {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+  .payment-input {
+    width: 100px;
+  }
+  .payment-unit {
+    color: #606266;
+    font-size: 14px;
+  }
+  .payment-select {
+    width: 120px!important;
+  }
+  .add-payment-btn,
+  .remove-payment-btn {
+    font-size: 18px;
+    padding: 0;
+  }
+  .remove-payment-btn {
+    color: #f56c6c;
+  }
+</style>

+ 55 - 0
src/views/rulesManagement/receiveTerms/components/searchForm.vue

@@ -0,0 +1,55 @@
+<!-- 搜索表单 -->
+<template>
+  <seekPage :seekList="seekList" :formLength="3" @search="search"></seekPage>
+</template>
+
+<script>
+  export default {
+    data() {
+      return {};
+    },
+    computed: {
+      seekList() {
+        return [
+          {
+            label: '关键词:',
+            value: 'searchName',
+            type: 'input',
+            placeholder: '编码、名称、型号、规格'
+          },
+          {
+            label: '下拉检索:',
+            value: 'searchType',
+            type: 'select',
+            placeholder: '请选择',
+            planList: [
+              { value: 1, label: '选项一' },
+              { value: 2, label: '选项二' },
+              { value: 3, label: '选项三' }
+            ]
+          },
+          {
+            label: '关键词:',
+            value: 'searchName2',
+            type: 'input',
+            placeholder: '编码、名称、型号、规格'
+          },
+          {
+            label: '创建时间:',
+            value: 'createTime',
+            type: 'date',
+            dateType: 'daterange',
+            placeholder: '',
+            width: 380,
+            valueAr: ['createTimeStart', 'createTimeEnd']
+          }
+        ];
+      }
+    },
+    methods: {
+      search(e) {
+        this.$emit('search', { ...e });
+      }
+    }
+  };
+</script>

+ 227 - 0
src/views/rulesManagement/receiveTerms/index.vue

@@ -0,0 +1,227 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never" v-loading="loading">
+      <div class="ele-border-lighter form-content" v-loading="loading">
+        <search-form @search="reload"> </search-form>
+
+        <!-- 数据表格 -->
+        <ele-pro-table
+          ref="table"
+          :columns="columns"
+          :datasource="datasource"
+          height="calc(100vh - 375px)"
+          full-height="calc(100vh - 116px)"
+          tool-class="ele-toolbar-form"
+          :selection.sync="selection"
+          :page-size="20"
+          @columns-change="handleColumnChange"
+          :cache-key="cacheKeyUrl"
+        >
+          <!-- 表头工具栏 -->
+          <template v-slot:toolbar>
+            <el-button
+              size="small"
+              type="primary"
+              icon="el-icon-plus"
+              class="ele-btn-icon"
+              @click="openEdit('add', {})"
+            >
+              新增
+            </el-button>
+          </template>
+
+          <!-- 操作列 -->
+          <template v-slot:action="{ row }">
+            <el-link
+              type="primary"
+              :underline="false"
+              icon="el-icon-view"
+              @click="openDetail(row)"
+            >
+              详情
+            </el-link>
+            <el-link
+              type="primary"
+              :underline="false"
+              icon="el-icon-edit"
+              @click="openEdit('edit', row)"
+            >
+              修改
+            </el-link>
+            <el-popconfirm
+              class="ele-action"
+              title="确定要删除此信息吗?"
+              @confirm="remove([row.id])"
+            >
+              <template v-slot:reference>
+                <el-link type="danger" :underline="false" icon="el-icon-delete">
+                  删除
+                </el-link>
+              </template>
+            </el-popconfirm>
+          </template>
+        </ele-pro-table>
+      </div>
+    </el-card>
+
+    <add-dialog ref="addDialogRef" @done="reload"></add-dialog>
+  </div>
+</template>
+
+<script>
+  import searchForm from './components/searchForm.vue';
+  import addDialog from './components/addDialog.vue';
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  import {
+    getTableList,
+    deleteInformation
+  } from '@/api/rulesManagement/receiveTerms';
+
+  export default {
+    mixins: [tabMixins],
+    components: {
+      searchForm,
+      addDialog
+    },
+    data() {
+      return {
+        selection: [],
+        loading: false,
+        columns: [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'code',
+            label: '编码',
+            align: 'center',
+            sortable: true,
+            showOverflowTooltip: true,
+            minWidth: 160
+          },
+          {
+            prop: 'name',
+            label: '收款条件名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160
+          },
+          {
+            prop: 'calcDateType',
+            label: '收款日计算日期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160,
+            formatter: (row) => {
+              const map = {
+                1: '订单日期',
+                2: '出库日期',
+                3: '应收单日期',
+                4: '开票日期',
+                5: '对账单日期'
+              };
+              return map[row.calcDateType] || '';
+            }
+          },
+          {
+            prop: 'paymentMethod',
+            label: '支付方式',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 140
+          },
+          {
+            prop: 'confirmType',
+            label: '收款日确认方式',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 140,
+            formatter: (row) => {
+              const map = {
+                1: '交易日',
+                2: 'X天后'
+              };
+              return map[row.confirmType] || '';
+            }
+          },
+          {
+            prop: 'confirmDesc',
+            label: '收款日确认方式描述',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 180
+          },
+          {
+            prop: 'createUserName',
+            label: '创建人',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 170,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            showOverflowTooltip: true,
+            fixed: 'right'
+          }
+        ],
+        cacheKeyUrl: 'eos-receiveTerms-list'
+      };
+    },
+    methods: {
+      /* 表格数据源 */
+      datasource({ page, limit, where, order }) {
+        return getTableList({
+          pageNum: page,
+          size: limit,
+          ...where
+        });
+      },
+
+      /* 刷新表格 */
+      reload(where) {
+        this.$refs.table.reload({ page: 1, where });
+      },
+
+      // 新增编辑
+      openEdit(type, row) {
+        this.$refs.addDialogRef.open(type, row);
+      },
+
+      // 查看详情
+      openDetail(row) {
+        this.$refs.addDialogRef.open('detail', row);
+      },
+
+      // 删除
+      remove(delData) {
+        deleteInformation(delData).then(() => {
+          this.$message.success('删除成功!');
+          this.reload();
+        });
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  :deep(.el-link--inner) {
+    margin-left: 0px !important;
+  }
+</style>

+ 305 - 0
src/views/system/organization/components/door-authorize.vue

@@ -0,0 +1,305 @@
+<!-- 用户编辑弹窗 -->
+<template>
+  <ele-modal
+    width="600px"
+    :visible="visible"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    title="授权"
+    @update:visible="updateVisible"
+    :maxable="true"
+  >
+    <el-form
+      ref="form"
+      :autoComplete="false"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+    >
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="授权类型:" prop="isPermanent">
+            <el-radio-group v-model="form.isPermanent">
+              <el-radio :label="0">临时授权</el-radio>
+              <el-radio :label="1">长期授权</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24" v-if="form.isPermanent == 0">
+          <el-form-item label="授权有效期:" prop="validTime">
+            <el-date-picker
+                v-model="form.validTime"
+                type="daterange"
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                value-format="yyyy-MM-dd HH:mm:ss"
+                style="width: 100%"
+              >
+              </el-date-picker>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template v-slot:footer>
+      <el-button @click="updateVisible(false)">取消</el-button>
+      <el-button type="primary" :loading="loading" @click="submitForm">
+        确定
+      </el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  import { listDevice, bindDevice, editBind } from '@/api/system/‌doorSecurity‌'
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  export default {
+    components: {  },
+    mixins: [tabMixins],
+    props: {
+      // 弹窗是否打开
+      visible: Boolean,
+      // isUpdate: Boolean,
+      // 修改回显的数据
+      current: Object,
+      list: Array,
+      deviceInfo: Object,
+    },
+    data() {
+      const defaultForm = {
+        isPermanent: 0,
+        validStart: '',
+        validEnd: '',
+        validTime: [],
+      };
+      return {
+        cacheKeyUrl: 'eos-64acd1e7-202605281106-user-door-authorize',
+        selection: [],
+        defaultForm,
+        // 表单数据
+        form: { ...defaultForm },
+        // 表单验证规则
+        rules: {
+          isPermanent: [{ required: true, message: '请选择授权类型', trigger: 'blur' }],
+          validTime: [{ required: true, message: '请选择授权时间', trigger: 'blur' }],
+        },
+        // 提交状态
+        loading: false,
+        // 是否是修改
+        isUpdate: false,
+        userInfo: {
+          postName: '',
+        },
+        // datasource: [],
+        deviceOptions: [],
+        bindDeviceData: [],
+      };
+    },
+    computed: {
+      // 是否开启响应式布局
+      styleResponsive() {
+        return this.$store.state.theme.styleResponsive;
+      },
+      columns() {
+        return [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'deviceName',
+            label: '设备名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 200
+          },
+          {
+            prop: 'ipAddress',
+            label: '设备IP',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 160
+          },
+          {
+            prop: 'port',
+            label: '端口',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 130
+          },
+          {
+            prop: 'doorCount',
+            label: '门数',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+          },
+          {
+            prop: 'model',
+            label: '型号',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 200,
+          },
+          {
+            prop: 'isBind',
+            label: '是否绑定',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+            formatter: (row) => {
+              return row.isBind ? '已绑定' : '未绑定';
+            }
+          },
+          {
+            prop: 'status',
+            label: '状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+            formatter: (row) => {
+              return row.status == 1 ? '在线' : '离线';
+            }
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 120,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            showOverflowTooltip: true,
+            fixed: 'right'
+          }
+        ]
+      }
+    },
+    mounted() {
+
+    },
+    methods: {
+      async datasource({ page, limit, where, order }) {
+        console.log(this.list, 'this.list');
+        const res = await listDevice({ ...where, ...order, pageNum: page, size: limit });
+        // 与已绑定设备对比,标记绑定状态
+        if (res.list && this.list.length > 0) {
+          console.log(this.list, 'this.list~~~');
+          const bindDeviceIds = this.list.map(item => item.deviceId);
+          console.log(bindDeviceIds, 'bindDeviceIds');
+          res.list = res.list.map(item => ({
+            ...item,
+            isBind: bindDeviceIds.includes(item.id) ? true : false
+          }));
+        }
+        console.log(res, 'res');
+        return res;
+      },
+ 
+      bindUserDevice(row) {
+        console.log(row, 'row');
+        bindDevice({
+          deviceId: row.id,
+          userId: this.current.id,
+          jobNumber: this.current.jobNumber,
+        }).then(res => {
+          console.log(res, 'res');
+          this.$message({
+            message: '绑定成功',
+            type: 'success'
+          });
+          row.isBind = true;
+     
+          this.$emit('success');
+        }).catch(err => {
+          console.log(err, 'err');
+          // this.$message({
+          //   message: '绑定失败',
+          //   type: 'error'
+          // });
+        })
+      },
+
+      submitForm() {
+        this.$refs.form?.validate(valid => {
+          if (valid) {
+            this.loading = true;
+            editBind({
+              deviceId: this.deviceInfo.deviceId,
+              id: this.deviceInfo.id,
+              isPermanent: this.form.isPermanent,
+              jobNumber: this.current.jobNumber,
+              userId: this.current.id,
+              validEnd: this.form.validTime.length > 0 ? this.form.validTime[1] : '',
+              validStart: this.form.validTime.length > 0 ? this.form.validTime[0] : '',
+            }).then(res => {
+              this.loading = false;
+              this.$message({
+                message: '操作成功',
+                type: 'success'
+              });
+              this.$emit('success');
+              this.updateVisible(false);
+            }).catch(err => {
+              this.loading = false;
+              // this.$message({
+                //   message: '绑定失败',
+                //   type: 'error'
+                // });
+            })
+          }
+        })
+      },
+      /* 保存编辑 */
+      /* 更新visible */
+      updateVisible(value) {
+        this.$emit('update:visible', value);
+      },
+    },
+    watch: {
+      visible(visible) {
+        console.log(visible, 'visible');
+        if (visible) {
+        
+        } else {
+          this.$refs.form?.clearValidate();
+          this.form = { ...this.defaultForm };
+        }
+      }
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  :deep(.el-input--medium .el-input__inner) {
+    height: auto !important;
+  }
+  :deep(.el-table) {
+    .el-form-item {
+      margin-bottom: 0;
+    }
+  }
+  :deep(.organizationList .el-input__inner) {
+    border: 0;
+    background: none;
+  }
+  :deep(.organizationList .el-input__suffix) {
+    display: none;
+  }
+  :deep(.organizationList .el-tag) {
+    background: none;
+  }
+</style>

+ 352 - 0
src/views/system/organization/components/door-bind.vue

@@ -0,0 +1,352 @@
+<!-- 用户编辑弹窗 -->
+<template>
+  <ele-modal
+    width="1100px"
+    :visible="visible"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    title="添加设备"
+    @update:visible="updateVisible"
+    :maxable="true"
+  >
+    <el-form
+      ref="form"
+      :autoComplete="false"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+    >
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="设备名称:" prop="deviceName">
+            <el-input
+              clearable
+              :maxlength="200"
+              v-model="form.deviceName"
+              placeholder="请输入设备名称"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="" prop="deviceName">
+            <!-- <el-input
+              clearable
+              :maxlength="200"
+              v-model="form.deviceName"
+              placeholder="请输入设备名称"
+            /> -->
+            <el-button type="primary" @click="handleSearch">
+              查询
+            </el-button>
+            <el-button type="primary" @click="handleReset">
+              重置
+            </el-button>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <ele-pro-table
+            ref="table"
+            :columns="columns"
+            :datasource="datasource"
+            height="calc(100vh - 405px)"
+            style="margin-bottom: 10px"
+            full-height="calc(100vh - 116px)"
+            tool-class="ele-toolbar-form"
+            :selection.sync="selection"
+            :page-size="20"
+            @columns-change="handleColumnChange"
+            :cache-key="cacheKeyUrl"
+          >
+            <!-- 表头工具栏 -->
+            <template v-slot:toolbar>
+
+            </template>
+
+            <!-- 操作列 -->
+            <template v-slot:action="{ row }">
+              <el-link
+                v-if="!row.isBind"
+                type="primary"
+                :underline="false"
+                icon="el-icon-edit"
+                @click="bindUserDevice(row)"
+              >
+                绑定
+              </el-link>
+              <!-- <el-popconfirm
+                class="ele-action"
+                title="确定要删除此信息吗?"
+                v-if="
+                  (isNeed_process_is_close &&
+                    [0, 3].includes(row.reviewStatus)) ||
+                  !isNeed_process_is_close
+                "
+                @confirm="remove([row.id])"
+              >
+                <template v-slot:reference>
+                  <el-link type="danger" :underline="false" icon="el-icon-delete">
+                    删除
+                  </el-link>
+                </template>
+              </el-popconfirm> -->
+            </template>
+          </ele-pro-table>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template v-slot:footer>
+      <el-button @click="updateVisible(false)">取消</el-button>
+      <el-button type="primary" :loading="loading" @click="updateVisible(false)">
+        确定
+      </el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  import { getUserDetail } from '@/api/system/organization';
+  import { listDoorUsers, listDevice, bindDevice } from '@/api/system/‌doorSecurity‌'
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  export default {
+    components: {  },
+    mixins: [tabMixins],
+    props: {
+      // 弹窗是否打开
+      visible: Boolean,
+      // isUpdate: Boolean,
+      // 修改回显的数据
+      current: Object,
+      list: Array,
+    },
+    data() {
+      const defaultForm = {
+        deviceName: '',
+      };
+      return {
+        cacheKeyUrl: 'eos-64acd1e7-202605281106-user-door-bind',
+        selection: [],
+        statusOptions: [
+          { 
+            label: '待同步',
+            value: 0
+
+          },
+          {
+            label: '已同步',
+            value: 1
+          },
+          {
+            label: '失败',
+            value: 2
+          }
+        ],
+        defaultForm,
+        // 表单数据
+        form: { ...defaultForm },
+        // 表单验证规则
+        rules: {},
+        // 提交状态
+        loading: false,
+        // 是否是修改
+        isUpdate: false,
+        userInfo: {
+          postName: '',
+        },
+        // datasource: [],
+        deviceOptions: [],
+        bindDeviceData: []
+      };
+    },
+    computed: {
+      // 是否开启响应式布局
+      styleResponsive() {
+        return this.$store.state.theme.styleResponsive;
+      },
+      columns() {
+        return [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'deviceName',
+            label: '设备名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 200
+          },
+          {
+            prop: 'ipAddress',
+            label: '设备IP',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 160
+          },
+          {
+            prop: 'port',
+            label: '端口',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 130
+          },
+          {
+            prop: 'doorCount',
+            label: '门数',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+          },
+          {
+            prop: 'model',
+            label: '型号',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 200,
+          },
+          {
+            prop: 'isBind',
+            label: '是否绑定',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+            formatter: (row) => {
+              return row.isBind ? '已绑定' : '未绑定';
+            }
+          },
+          {
+            prop: 'status',
+            label: '状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+            formatter: (row) => {
+              return row.status == 1 ? '在线' : '离线';
+            }
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 120,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            showOverflowTooltip: true,
+            fixed: 'right'
+          }
+        ]
+      }
+    },
+    mounted() {
+
+    },
+    methods: {
+      handleSearch() {
+        this.reload(this.form);
+      },
+      handleReset() {
+        this.form = { ...this.defaultForm };
+        this.reload(this.form);
+      },
+      async datasource({ page, limit, where, order }) {
+        console.log(this.list, 'this.list');
+        const res = await listDevice({ ...where, ...order, pageNum: page, size: limit });
+        // 与已绑定设备对比,标记绑定状态
+        if (res.list && this.list.length > 0) {
+          console.log(this.list, 'this.list~~~');
+          const bindDeviceIds = this.list.map(item => item.deviceId);
+          console.log(bindDeviceIds, 'bindDeviceIds');
+          res.list = res.list.map(item => ({
+            ...item,
+            isBind: bindDeviceIds.includes(item.id) ? true : false
+          }));
+        }
+        console.log(res, 'res');
+        return res;
+      },
+      reload(where) {
+        this.$refs.table.reload({ pageNum: 1, where: where });
+      },
+      bindUserDevice(row) {
+        console.log(row, 'row');
+        bindDevice({
+          deviceId: row.id,
+          userId: this.current.id,
+          jobNumber: this.current.jobNumber,
+        }).then(res => {
+          console.log(res, 'res');
+          this.$message({
+            message: '绑定成功',
+            type: 'success'
+          });
+          row.isBind = true;
+          this.reload();
+          this.$emit('success');
+        }).catch(err => {
+          console.log(err, 'err');
+          // this.$message({
+          //   message: '绑定失败',
+          //   type: 'error'
+          // });
+        })
+      },
+
+      async getUserDetail() {
+        if (!this.current.id) {
+          return;
+        }
+        this.userInfo = await getUserDetail(this.current.id);
+      },
+      /* 保存编辑 */
+      /* 更新visible */
+      updateVisible(value) {
+        this.$emit('update:visible', value);
+      },
+    },
+    watch: {
+      visible(visible) {
+        console.log(visible, 'visible');
+        if (visible) {
+          this.reload();
+        } else {
+          this.$refs.form?.clearValidate();
+          this.form = { ...this.defaultForm };
+        }
+      }
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  :deep(.el-input--medium .el-input__inner) {
+    height: auto !important;
+  }
+  :deep(.el-table) {
+    .el-form-item {
+      margin-bottom: 0;
+    }
+  }
+  :deep(.organizationList .el-input__inner) {
+    border: 0;
+    background: none;
+  }
+  :deep(.organizationList .el-input__suffix) {
+    display: none;
+  }
+  :deep(.organizationList .el-tag) {
+    background: none;
+  }
+</style>

+ 376 - 0
src/views/system/organization/components/door-modal.vue

@@ -0,0 +1,376 @@
+<!-- 用户编辑弹窗 -->
+<template>
+  <ele-modal
+    width="1100px"
+    :visible="visible"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    title="门禁"
+    @update:visible="updateVisible"
+    :maxable="true"
+  >
+    <el-form
+      ref="form"
+      :autoComplete="false"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+    >
+      <el-row>
+        <el-col :span="24" style="margin-bottom: 20px;">
+          <!-- <el-form-item label="设备:" prop="deviceId">
+            <el-select
+              v-model="form.deviceId"
+              placeholder="请选择"
+              style="width: 100%"
+              @change="handleDeviceChange"
+            >
+              <el-option
+                v-for="item in deviceOptions"
+                :key="item.id"
+                :label="item.deviceName"
+                :value="item.id"
+              >
+              </el-option>
+            </el-select>
+            
+          </el-form-item> -->
+          <!-- <el-form-item label="" prop="deviceId"> -->
+            <!-- <el-select
+              v-model="form.deviceId"
+              placeholder="请选择"
+              style="width: 100%"
+              @change="handleDeviceChange"
+            >
+              <el-option
+                v-for="item in deviceOptions"
+                :key="item.id"
+                :label="item.deviceName"
+                :value="item.id"
+              >
+              </el-option>
+            </el-select> -->
+            <el-button type="primary" @click="handleBindDevice">添加设备</el-button>
+          <!-- </el-form-item> -->
+        </el-col>
+        <el-col :span="24">
+          <ele-pro-table
+            ref="table"
+            :columns="columns"
+            :datasource="datasource"
+            height="calc(100vh - 405px)"
+            style="margin-bottom: 10px"
+            full-height="calc(100vh - 116px)"
+            tool-class="ele-toolbar-form"
+            :selection.sync="selection"
+            :page-size="20"
+            @columns-change="handleColumnChange"
+            :cache-key="cacheKeyUrl"
+            :needPage="false"
+          >
+            <!-- 表头工具栏 -->
+            <template v-slot:toolbar>
+
+            </template>
+
+            <!-- 操作列 -->
+            <template v-slot:action="{ row }">
+              <el-link
+                type="primary"
+                :underline="false"
+                @click="handleAuthorize(row)"
+              >
+                授权
+              </el-link>
+              <el-link
+                type="primary"
+                :underline="false"
+                @click="handleSync(row)"
+              >
+                同步
+              </el-link>
+              <el-popconfirm
+                class="ele-action"
+                title="确定要解绑吗?"
+                @confirm="unbind(row)"
+              >
+                <template v-slot:reference>
+                  <el-link type="danger" :underline="false">
+                    解绑
+                  </el-link>
+                </template>
+              </el-popconfirm>
+            </template>
+          </ele-pro-table>
+        </el-col>
+      </el-row>
+    </el-form>
+    <template v-slot:footer>
+      <el-button @click="updateVisible(false)">取消</el-button>
+      <el-button type="primary" :loading="loading" @click="updateVisible(false)">
+        确定
+      </el-button>
+    </template>
+    <!-- 授权 -->
+    <doorAuthorize ref="doorAuthorizeRef" :current="current" :deviceInfo="deviceInfo" :list="datasource" :visible.sync="showAuthorize" @success="getData"></doorAuthorize>
+    <!-- 绑定 -->
+    <doorBind ref="doorBindRef" :current="current" :list="datasource" :visible.sync="showBind" @success="getData"></doorBind>
+  </ele-modal>
+</template>
+
+<script>
+  // import { emailReg, phoneReg } from 'ele-admin';
+  import doorAuthorize from './door-authorize.vue';
+  import doorBind from './door-bind.vue';
+  import { addUsers, putUsers, getById } from '@/api/system/user';
+  import { getUserDetail } from '@/api/system/organization';
+  import { listDoorUsers, listDevice, syncDevice, unbindDevice } from '@/api/system/‌doorSecurity‌'
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  export default {
+    components: { doorAuthorize, doorBind },
+    mixins: [tabMixins],
+    props: {
+      // 弹窗是否打开
+      visible: Boolean,
+      // 修改回显的数据
+      current: Object,
+    },
+    data() {
+      const defaultForm = {
+        deviceId: '',
+      };
+      return {
+        showAuthorize: false,
+        deviceInfo: {},
+        cacheKeyUrl: 'eos-64acd1e7-202605271646-user-door',
+        selection: [],
+        statusOptions: [
+          { 
+            label: '待同步',
+            value: 0
+
+          },
+          {
+            label: '已同步',
+            value: 1
+          },
+          {
+            label: '失败',
+            value: 2
+          }
+        ],
+        defaultForm,
+        // 表单数据
+        form: { ...defaultForm },
+        // 表单验证规则
+        rules: {},
+        // 提交状态
+        loading: false,
+        // 是否是修改
+        userInfo: {
+          postName: '',
+        },
+        datasource: [],
+        deviceOptions: [],
+        showBind: false,
+      };
+    },
+    computed: {
+      // 是否开启响应式布局
+      styleResponsive() {
+        return this.$store.state.theme.styleResponsive;
+      },
+      columns() {
+        return [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center'
+          },
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'deviceName',
+            label: '设备名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 200
+          },
+          {
+            prop: 'ipAddress',
+            label: '设备IP',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 160
+          },
+          {
+            prop: 'port',
+            label: '端口',
+            align: 'center',
+            showOverflowTooltip: true,
+            sortable: true,
+            minWidth: 130
+          },
+          {
+            prop: 'isPermanent',
+            label: '是否长期授权',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+            formatter: (row) => {
+              return row.isPermanent === 1 ? '是' : '否';
+            }
+          },
+          {
+            prop: 'validStart',
+            label: '有效期',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 200,
+            formatter: (row) => {
+              return row.validStart ? row.validStart + '~' + row.validEnd : '';
+            }
+          },
+          {
+            prop: 'syncStatus',
+            label: '状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 130,
+            formatter: (row) => {
+              return this.statusOptions.find(item => item.value === row.syncStatus)?.label || '';
+            }
+          },
+          {
+            prop: 'syncMsg',
+            label: '同步日志',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 150
+          },
+          {
+            prop: 'createTime',
+            label: '创建时间',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 170
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 200,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            showOverflowTooltip: true,
+            fixed: 'right'
+          }
+        ]
+      }
+    },
+    mounted() {
+      console.log('mounted~~~');
+      // this.getData();
+    },
+    methods: {
+      unbind(row) {
+        unbindDevice(row.id).then(res => {
+          this.$message({
+            message: '解绑成功',
+            type: 'success'
+          });
+          this.getData();
+        }).catch(err => {
+        })
+      },
+      handleBindDevice() {
+        this.showBind = true;
+      },
+      async handleSync(row) {
+        await syncDevice(row.id);
+        this.$message({
+          message: '同步成功',
+          type: 'success'
+        });
+        this.getData();
+      },
+      handleAuthorize(row) {
+        this.deviceInfo = row;
+        this.showAuthorize = true;
+        console.log(row, 'row');
+      },
+      handleDeviceChange(val) {
+        console.log(val, 'val');
+        this.getData();
+      },
+      getData() {
+        listDoorUsers({ userId: this.current.id, ...this.form }).then(res => {
+          console.log(res, 'res');
+          this.datasource = res;
+        })
+      },
+      getDeviceList() {
+        listDevice({
+          size: 9999,
+          pageNum: 1,
+        }).then(res => {
+          console.log(res, 'res');
+          this.deviceOptions = res.list;
+        })
+      },
+      async getUserDetail() {
+        if (!this.form.mainUserId) {
+          return;
+        }
+        this.userInfo = await getUserDetail(this.form.mainUserId);
+      },
+      /* 更新visible */
+      updateVisible(value) {
+        this.$emit('update:visible', value);
+      },
+    },
+    watch: {
+      visible(visible) {
+        console.log(visible, 'visible');
+        if (visible) {
+          this.getDeviceList();
+          this.getData();
+        } else {
+          this.$refs.form?.clearValidate();
+          this.form = { ...this.defaultForm };
+        }
+      }
+    }
+  };
+</script>
+<style lang="scss" scoped>
+  :deep(.el-input--medium .el-input__inner) {
+    height: auto !important;
+  }
+  :deep(.el-table) {
+    .el-form-item {
+      margin-bottom: 0;
+    }
+  }
+  :deep(.organizationList .el-input__inner) {
+    border: 0;
+    background: none;
+  }
+  :deep(.organizationList .el-input__suffix) {
+    display: none;
+  }
+  :deep(.organizationList .el-tag) {
+    background: none;
+  }
+</style>

+ 4 - 0
src/views/system/organization/components/org-user-edit.vue

@@ -1172,6 +1172,7 @@
   import {
     getUserDetail,
     saveOrUpdateUser,
+    createPersonal,
     checkExistence
   } from '@/api/system/organization';
   import { getFactoryarea, getProfessionPageList } from '@/api/factoryModel';
@@ -2108,6 +2109,9 @@
                 this.$message.success('人员信息编辑成功');
               } else {
                 this.$message.success('人员新增成功');
+                //新建人员后创建个人文件夹
+
+                createPersonal(msg);
               }
               this.updateVisible(false);
               this.$emit('done');

+ 19 - 2
src/views/system/organization/components/org-user-list.vue

@@ -119,6 +119,14 @@
         >
           新建账号
         </el-link>
+        <!-- <el-link
+          type="primary"
+          :underline="false"
+          icon="el-icon-key"
+          @click="openDoor(row)"
+        >
+          门禁
+        </el-link> -->
         <el-popconfirm
           class="ele-action"
           title="确定要删除此用户吗?"
@@ -199,6 +207,7 @@
       ref="criticalProcessRef"
       @chooseProcess="chooseProcess"
     ></critical-process>
+    <DoorModal ref="doorModalRef" :visible.sync="showDoor" :current="current" />
   </div>
 </template>
 
@@ -220,6 +229,7 @@
   import dictMixins from '@/mixins/dictMixins';
   import { getFactoryarea } from '@/api/factoryModel';
   import criticalProcess from './criticalProcess.vue';
+  import DoorModal from './door-modal.vue';
 
   export default {
     mixins: [tabMixins, dictMixins],
@@ -229,7 +239,8 @@
       OrgUserEdit,
       addUsers,
       UserSearch,
-      criticalProcess
+      criticalProcess,
+      DoorModal
     },
     props: {
       // 机构id
@@ -386,7 +397,7 @@
           {
             columnKey: 'action',
             label: '操作',
-            width: 200,
+            width: 260,
             align: 'left',
             resizable: false,
             fixed: 'right',
@@ -398,6 +409,7 @@
     },
     data() {
       return {
+        showDoor: false,
         moudleName: 'mainUser',
         showEdit1: false,
         userShow: false,
@@ -487,6 +499,11 @@
       };
     },
     methods: {
+      openDoor(row) {
+        console.log(row);
+        this.current = row;
+        this.showDoor = true;
+      },
       allPushBtn() {
         const dataId = this.selection.map((v) => v.id);
         employeePush(dataId)