yusheng 1 anno fa
parent
commit
b92955a0f0

+ 67 - 0
src/api/bpm/components/changeManage/index.js

@@ -0,0 +1,67 @@
+import request from '@/utils/request';
+/**
+ * 获取信息列表
+ */
+export async function getTableList(params) {
+  const res = await request.get(`/eom/changerecord/page`, { params });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 获取信息详情
+ */
+export async function getDetail(id) {
+  const res = await request.get(`/eom/changerecord/getById/${id}`, {});
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 更新信息
+ */
+export async function UpdateInformation(data) {
+  const res = await request.put(`/eom/changerecord/update`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 新增信息
+ */
+export async function addInformation(data) {
+  const res = await request.post(`/eom/changerecord/save`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 删除
+ */
+export async function deleteInformation(data) {
+  const res = await request.delete('/eom/changerecord/delete', { data });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 获取变更记录
+ */
+export async function changeHistory(id) {
+  const res = await request.get(`/eom/changerecord/changeHistory/${id}`, {});
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+

+ 4 - 0
src/enum/dict.js

@@ -169,3 +169,7 @@ export const lbjtList = {
   3: '外协件',
   4: '受托件'
 };
+
+
+//变更类型
+export const relationTypeList = [{ value: 100, label: '采购订单' }];

+ 0 - 1
src/main.js

@@ -81,7 +81,6 @@ Vue.use(VueClipboard);
 let instance = null;
 
 function render(props = {}) {
-  console.log(router, 2222);
   const { container, routerBase } = props;
   // const router = new VueRouter({
   //   base: window.__POWERED_BY_QIANKUN__ ? routerBase : process.env.BASE_URL,

+ 209 - 0
src/mixins/tableColumnsMixin.js

@@ -0,0 +1,209 @@
+import request from '@/utils/request';
+
+export default {
+  data() {
+    return {
+      newColumns: []
+    };
+  },
+  created() {
+    //从服务器获取缓存列表配置
+    this.getTabColumns();
+    // 创建防抖函数并绑定this
+    this.debouncedHandleColumnChange = this.debounce(
+      this.handleColumnChangeImpl,
+      1000
+    );
+  },
+  methods: {
+    // 实际的列变更处理逻辑
+    handleColumnChangeImpl() {
+      try {
+        const list = this.getStorage(this.cacheKeyUrl + 'Cols');
+        if (list) {
+          this.saveColumns(list);
+        }
+      } catch (error) {
+        console.error('处理列配置出错:', error);
+      }
+    },
+
+    // 列表变化回调
+    handleColumnChange() {
+      this.debouncedHandleColumnChange();
+    },
+
+    // 获取table-column配置
+    async getTabColumns() {
+      const res = await this.getByTableId(this.cacheKeyUrl);
+      if (res?.columnConfig?.length > 0) {
+        //对比接口返回和本地columns
+        let { nlist, type } = this.columnsContrast(res.columnConfig);
+        //有更新则更新服务缓存配置
+        if (type) {
+          this.saveColumns(nlist);
+        }
+        this.setStorage(this.cacheKeyUrl + 'Cols', nlist);
+        // 更新列
+        if (this._computedWatchers && this._computedWatchers.columns) {
+          // console.log('columns 是计算属性');
+          this.columnsVersion++;
+        } else {
+          // console.log('columns 是 data 属性');
+          this.columns = [...this.columns];
+          this.newColumns = [...this.newColumns];
+        }
+      }
+    },
+    //服务器和本地配置columns对比
+    columnsContrast(list) {
+      const key = 'label';
+      var updateType = 0;
+      let sList = list.filter((d, i, r) => {
+        return d[key];
+      });
+      let devColumns =
+        this.newColumns?.length > 0 ? this.newColumns : this.columns;
+      let dList = devColumns.filter((d, i, r) => {
+        return d[key] && d[key] !== '序号';
+      });
+      const keysA = new Set(sList.map((item) => item[key]));
+      const keysB = new Set(dList.map((item) => item[key]));
+      // 本地 比 缓存服务端 多的对象(新增)
+      const added = dList.filter((item) => {
+        return !keysA.has(item[key]) && (item.prop || item.label === '操作');
+      });
+      // 本地 比 缓存服务端 少的对象(删除)
+      const removed = sList.filter((item) => !keysB.has(item[key]));
+      const removedPropSet = new Set(removed.map((item) => item[key]));
+      // 删除 缓存中 中被移除的对象
+      const keptA = list.filter((item) => !removedPropSet.has(item[key]));
+      added.forEach((item) => {
+        //新增columns字段prop参数为必填
+        if (item.prop) {
+          item.id = item.prop;
+        } else if (item.columnKey) {
+          item.id = item.columnKey;
+        }
+        item.checked = true;
+      });
+
+      if (added.length > 0 || removed.length > 0) {
+        updateType = 1;
+      }
+
+      // 更新项:key 存在但内容变化
+      const dMap = new Map(dList.map((item) => [item[key], item]));
+      const updated = keptA.map((sItem) => {
+        const dItem = dMap.get(sItem[key]);
+        if (dItem && dItem.prop && sItem.prop !== dItem.prop) {
+          updateType = 1;
+          // 记录旧值和新值
+          const oldValue = sItem.prop;
+          const newValue = dItem.prop;
+          // 遍历所有属性,动态替换匹配旧值的字段
+          const updatedItem = { ...sItem };
+          Object.keys(updatedItem).forEach((k) => {
+            if (updatedItem[k] === oldValue) {
+              updatedItem[k] = newValue;
+            }
+          });
+          return updatedItem;
+        }
+        return sItem;
+      });
+
+      // 合并保留的对象和新增的对象
+      return { nlist: [...updated, ...added], type: updateType };
+    },
+
+    // 提交columns配置
+    async saveColumns(e) {
+      const data = {
+        tableId: this.cacheKeyUrl,
+        columnConfig: e
+      };
+      const msg = await this.saveTableConfig(data);
+      // console.log('列配置保存成功:', msg);
+      return msg;
+    },
+
+    //获取localstorage缓存
+    setStorage(key, value) {
+      try {
+        localStorage.setItem(key, JSON.stringify(value));
+      } catch (e) {
+        console.log('LocalStorage 存储错误:', e);
+        if (e.name === 'QuotaExceededError') {
+          this.clearCacheByPrefix(); //缓存不足,清除
+          localStorage.setItem(key, JSON.stringify(value));
+        }
+      }
+    },
+
+    //缓存不足清除缓存
+    clearCacheByPrefix() {
+      const prefix = 'Cols'; // 标识后缀
+      Object.keys(localStorage).forEach((key) => {
+        if (key.endsWith(prefix)) {
+          localStorage.removeItem(key);
+          // console.log(`已清除缓存: ${key}`);
+        }
+      });
+      // console.log('缓存清除完成');
+    },
+
+    //设置localstorage缓存
+    getStorage(key) {
+      try {
+        const value = localStorage.getItem(key);
+        return value ? JSON.parse(value) : null;
+      } catch (e) {
+        console.error('LocalStorage 解析错误:', e);
+        return null;
+      }
+    },
+
+    //防抖函数
+    debounce(fn, delay) {
+      let timer = null;
+      return (...args) => {
+        clearTimeout(timer);
+        timer = setTimeout(() => {
+          fn.apply(this, args);
+        }, delay);
+      };
+    },
+
+    //获取column记录接口
+    async getByTableId(key) {
+      try {
+        const res = await request.get(
+          `/sys/table-config/getByTableId/${key}`,
+          {}
+        );
+        if (res.data.code == 0) {
+          return res.data.data;
+        }
+      } catch (error) {
+        console.error('获取列配置失败:', error);
+      }
+    },
+
+    // 添加column记录接口
+    async saveTableConfig(data) {
+      try {
+        const res = await request({
+          url: '/sys/table-config/save',
+          method: 'post',
+          data
+        });
+        if (res.data.code == 0) {
+          return res.data.data;
+        }
+      } catch (error) {
+        console.error('保存列配置失败:', error);
+      }
+    }
+  }
+};

+ 107 - 0
src/views/bpm/handleTask/components/changeManage/detailDialog.vue

@@ -0,0 +1,107 @@
+<template>
+  <div>
+    <el-form ref="form" class="el-form-box" :model="form" label-width="90px">
+      <headerTitle title="基本信息"></headerTitle>
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="来源类型" prop="relationType">
+            <el-select
+              v-model="form.relationType"
+              @change="relationTypeChange"
+              style="width: 100%"
+              disabled
+            >
+              <el-option
+                :value="item.value"
+                :label="item.label"
+                v-for="(item, index) in relationTypeList"
+                :key="index"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+
+        <!-- <el-col :span="12">
+          <el-form-item label="变更合同" prop="contractName">
+            <el-input
+              v-model="form.contractName"
+              @click.native="selectContract"
+              readonly
+              :disabled="dialogType == 'view'"
+            ></el-input>
+          </el-form-item>
+        </el-col> -->
+        <el-col :span="12" v-if="form.relationType == 100">
+          <el-form-item label="变更订单" prop="relationCode">
+            <el-input
+              v-model="form.relationCode"
+              disabled
+            ></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="附件" prop="file">
+            <fileMain v-model="form.file" type="view"></fileMain>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="变更原因" prop="reason">
+            <el-input v-model="form.reason" disabled type="textarea"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="变更描述" prop="remark">
+            <el-input v-model="form.remark" disabled type="remark"></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+  </div>
+</template>
+<script>
+  import { mapGetters } from 'vuex';
+  import { getDetail } from '@/api/bpm/components/changeManage/index.js';
+  import fileMain from '@/components/addDoc/index.vue';
+  import { relationTypeList } from '@/enum/dict.js';
+
+  const defForm = {
+    name: '',
+    changeCode: '',
+    file: [], //条件
+    remark: '',
+    type: '',
+    describes: '',
+    relationId: '',
+    relationName: '',
+    relationCode: '',
+    relationType: ''
+  };
+  export default {
+    components: { fileMain },
+    computed: {
+      ...mapGetters(['user'])
+    },
+    props: {
+      businessId: {
+        default: ''
+      }
+    },
+    data() {
+      return {
+        form: {
+          ...defForm
+        }
+      };
+    },
+    created() {
+      this.getInfo(this.businessId);
+    },
+    methods: {
+      //获取详情
+      async getInfo(id) {
+        this.form = await getDetail(id);
+      }
+    }
+  };
+</script>
+<style scoped lang="scss"></style>

+ 154 - 0
src/views/bpm/handleTask/components/changeManage/submit.vue

@@ -0,0 +1,154 @@
+<template>
+  <el-col :span="16" :offset="6">
+    <el-form label-width="100px" ref="formRef" :model="form">
+      <el-form-item
+        label="审批建议"
+
+        style="margin-bottom: 20px"
+        :rules="{
+          required: true,
+          message: '请选择',
+          trigger: 'change'
+        }"
+      >
+        <el-input
+          type="textarea"
+          v-model="form.reason"
+          placeholder="请输入审批建议"
+        />
+      </el-form-item>
+    </el-form>
+    <div style="margin-left: 10%; margin-bottom: 20px; font-size: 14px">
+      <el-button
+        icon="el-icon-edit-outline"
+        type="success"
+        size="mini"
+        @click="handleAudit(1)"
+        >通过
+      </el-button>
+      <el-button
+        icon="el-icon-circle-close"
+        type="danger"
+        size="mini"
+        @click="handleAudit(0)"
+       
+        >驳回
+      </el-button>
+
+      <el-dropdown @command="(command) => handleCommand(command)" style="margin-left: 30px;">
+        <span class="el-dropdown-link">更多<i class="el-icon-arrow-down el-icon--right"></i></span>
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item command="cancel">作废</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+    
+    </div>
+  </el-col>
+</template>
+
+<script>
+  import { UpdateInformation, cancel } from '@/api/bpm/components/contractManage/contractBook';
+  import {approveTaskWithVariables, rejectTask} from '@/api/bpm/task';
+  import { listAllUserBind } from '@/api/system/organization';
+
+  // 流程实例的详情页,可用于审批
+  export default {
+    name: '',
+    components: {
+      //   Parser
+    },
+    props: {
+      businessId: {
+        default: ''
+      },
+      taskId: {
+        default: ''
+      },
+      id: {
+        default: ''
+      },
+      taskDefinitionKey: {
+        default: ''
+      }
+    },
+    data() {
+      return {
+        form: {
+          technicianId: '',
+          reason: ''
+        },
+        userOptions: []
+      };
+    },
+    created() {
+
+      this.userOptions = [];
+      listAllUserBind().then((data) => {
+        this.userOptions.push(...data);
+      });
+    },
+    methods: {
+      /** 处理转办审批人 */
+      handleUpdateAssignee() {
+        this.$emit('handleUpdateAssignee');
+      },
+      /** 退回 */
+      handleBackList() {
+        this.$emit('handleBackList');
+      },
+
+
+      async handleAudit(status) {
+        let variables = {
+          pass: !!status
+        };
+
+        let API = !!status ? approveTaskWithVariables : rejectTask;
+        API({
+          id: this.taskId,
+          reason: this.form.reason,
+          variables
+        }).then((res) => {
+          if (res.data.code != '-1') {
+            this.$emit('handleAudit', {
+              status,
+              title: status === 0 ? '驳回' : ''
+            });
+          }
+        });
+      },
+
+      getTableValue() {
+        return new Promise((resolve, reject) => {
+          this.$emit('getTableValue', async (data) => {
+            resolve(await data);
+          });
+        });
+      },
+
+      //更多
+      handleCommand(command) {
+        if (command === 'cancel') {
+          this.$confirm("是否确认作废?", {
+            type: 'warning',
+            cancelButtonText: '取消',
+            confirmButtonText: '确定'
+          }).then(() => {
+            cancel({
+              id: this.taskId,
+              reason: this.form.reason,
+              businessId: this.businessId,
+            }).then(() => {
+              this.$emit('handleClose');
+            }).catch(() => {
+              this.$message.error("流程作废失败");
+            });
+          }).catch(() => {});
+        }
+      },
+
+    }
+  };
+</script>
+
+<style lang="scss"></style>

+ 15 - 11
src/views/bpm/handleTask/components/saleOrder/invoice/detailDialog.vue

@@ -49,6 +49,13 @@
           >
             {{ form.receiveAddress }}
           </el-form-item>
+          <el-form-item
+            label="打印编码:"
+            prop="printNo"
+            style="margin-bottom: 5px"
+          >
+            {{ form.printNo }}
+          </el-form-item>
         </el-col>
 
         <el-col :span="8">
@@ -112,16 +119,11 @@
       ref="table"
       :needPage="false"
       :columns="competAnalysisListcolumns"
-      :toolkit="[]"
+      @columns-change="handleColumnChange"
+      :cache-key="cacheKeyUrl"
       :datasource="detailData.productList"
       row-key="id"
     >
-      <!-- <template v-slot:toolbar>
-        <div class="headbox">
-        <span class="amount">总计:{{detailData.totalAmount}}元</span>
-        <span class="amount">应付金额:{{detailData.payAmount}}元</span>
-      </div>
-      </template> -->
       <template v-slot:stockLedger="scope">
         <el-popover placement="right" width="60%" trigger="hover">
           <ele-pro-table
@@ -132,7 +134,6 @@
             :columns="childrenColumns"
             :toolkit="[]"
             :datasource="scope.row.sendProductDetail"
-            cache-key="stockLedgerRoleTable"
             class="time-form"
           >
           </ele-pro-table>
@@ -168,7 +169,7 @@
         :bizType="3"
         :saleProductList="form.productList"
         type="销售发货出库"
-        v-if="!isView&&taskDefinitionKey == 'storemanApprove'"
+        v-if="!isView && taskDefinitionKey == 'storemanApprove'"
       ></add>
     </keep-alive>
     <detailDialog
@@ -193,15 +194,18 @@
   import fileMain from '@/components/addDoc/index.vue';
   import { lbjtList } from '@/enum/dict.js';
   import detailDialog from '@/views/bpm/outgoingManagement/details.vue';
+  import tabMixins from '@/mixins/tableColumnsMixin';
 
   export default {
-    mixins: [dictMixins],
+    mixins: [dictMixins, tabMixins],
     components: {
       fileMain,
-      add,detailDialog
+      add,
+      detailDialog
     },
     data() {
       return {
+        cacheKeyUrl: 'wt-saleManage-invoice-inventoryTableDetail',
         activeComp: 'main',
         tabOptions: [{ key: 'main', name: '发货单详情' }],
         reviewStatusEnum,

+ 1 - 11
src/views/bpm/handleTask/components/saleOrder/invoice/inventoryTable.vue

@@ -29,17 +29,7 @@
           :prop="'datasource.' + $index + '.technicalDrawings'"
         >
           <fileMain v-model="row.technicalDrawings" type="view"></fileMain>
-<!--          <div v-if="row.technicalDrawings && row.technicalDrawings?.length">-->
-<!--            <el-link-->
-<!--              v-for="link in row.technicalDrawings"-->
-<!--              :key="link.id"-->
-<!--              type="primary"-->
-<!--              :underline="false"-->
-<!--              @click="downloadFile(link)"-->
-<!--            >-->
-<!--              {{ link.name }}</el-link-->
-<!--            >-->
-<!--          </div>-->
+
         </el-form-item>
       </template>
       <template v-slot:remark="{ row, $index }">

+ 2 - 2
src/views/bpm/outgoingManagement/outbound.vue

@@ -116,7 +116,7 @@
                 :show-overflow-tooltip="true"></el-table-column>
               <el-table-column label="牌号" align="center" prop="brandNum"
                 :show-overflow-tooltip="true"></el-table-column>
-              <el-table-column v-for="(item, index) in newColumns" :label="item.label" :align="item.align"
+              <el-table-column v-for="(item, index) in newColumns" :label="item.label" :align="item.align" :key="index"
                 :prop="item.prop" :show-overflow-tooltip="item.showOverflowTooltip"></el-table-column>
               <el-table-column label="批次号" prop="batchNo" align="center" :show-overflow-tooltip="true">
               </el-table-column>
@@ -131,7 +131,7 @@
               <el-table-column label="单价" prop="price" align="center">
                 <template slot-scope="{ row }">
                   <template>
-                    {{ row.price ? row.price : '-' + '元' }}/{{
+                    {{ row.price ? row.price : ' ' + '元' }}/{{
                       row.measureUnit
                     }}
                   </template>

+ 25 - 11
src/views/home/index.vue

@@ -196,7 +196,7 @@
               v-for="(item, index) in list"
               :class="[(index + 1) % 3 == 0 ? 'item margin_0' : 'item']"
               @click="openUrl(item)"
-            > 
+            >
               <div><img :src="item.img" /></div>
               <div>{{ item.name }}</div>
             </div>
@@ -264,7 +264,9 @@
 <script>
   import { getTodoTaskPage, notifyMessagePageAPI } from '@/api/bpm/task';
   import { mapGetters } from 'vuex';
-  import detail from '@/views/bpm/processInstance/detail.vue';
+  // import detail from '@/views/bpm/processInstance/detail.vue';
+  import detail from '@/views/bpm/done/detailDialog.vue';
+
   import handleTask from '@/views/bpm/handleTask/index.vue';
   import { deepClone } from 'ele-admin/lib/utils/core';
   import vueSeamlessScroll from 'vue-seamless-scroll';
@@ -281,7 +283,7 @@
   import xyy from '@/assets/xyy.jpg';
   import draggable from 'vuedraggable';
   import handleFormParserTask from '@/views/bpm/handleTask/formParser/formParserDialog.vue';
-  import { getCurrentUser,setCurrentUser } from '@/utils/token-util';
+  import { getCurrentUser, setCurrentUser } from '@/utils/token-util';
 
   export default {
     name: 'index',
@@ -358,6 +360,20 @@
             showOverflowTooltip: true,
             minWidth: 120
           },
+          {
+            prop: 'businessName',
+            label: '单据名称',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
+          {
+            prop: 'businessType',
+            label: '单据类型',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 120
+          },
           {
             prop: 'processInstance.startUserNickname',
             label: '流程发起人',
@@ -397,7 +413,7 @@
     computed: {
       ...mapGetters(['user']),
       getRoleName() {
-        let currentUser = getCurrentUser()
+        let currentUser = getCurrentUser();
         return (list = [], type) => {
           const dept = list.find(
             (item) => item.groupId == currentUser.currentGroupId
@@ -426,13 +442,13 @@
     methods: {
       openUrl(item) {
         // 统一门户配置
-        if(item.architType==='1'){
-           // bs门户配置
+        if (item.architType === '1') {
+          // bs门户配置
           window.open(item.linkUrl);
-        }else{
+        } else {
           let url = item.linkUrl.split('//');
           window.open(url[1], '_blank');
-           // cs门户配置
+          // cs门户配置
 
           //  const link = document.createElement('a');
           //   // 6. 设置链接属性
@@ -440,8 +456,6 @@
           //   link.download = '自定义文件名.zip'; // 可以设置不同的下载文件名
           //   link.style.display = 'none';
         }
-           
-
       },
       async getPages() {
         let { list } = await getList({ pageNum: 1, size: 9999 });
@@ -587,7 +601,7 @@
             pcViewRouter: row.pcViewRouter
           });
         } else {
-          this.$refs.detailRef.open(row.processInstance.id);
+          this.$refs.detailRef.open(row);
         }
       },