Sfoglia il codice sorgente

调拨,消息公司模块

yangg 11 mesi fa
parent
commit
497a8b74b0

+ 41 - 1
src/api/company.js

@@ -63,4 +63,44 @@ export function getOne(id) {
     url: `/admin/erp/company/getOne/${id}`,
     method: 'get',
   })
-}
+}
+
+/* 校验营业执照 */
+export function checkLicense(parmas) {
+  return request({
+    url: `/admin/erp/company/checkLicense`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/* 校验身份证 */
+export function checkIdCardOpposite(parmas,type) {
+  return request({
+    url: `/admin/erp/company/checkIdCardOpposite/${type}`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/* 获取模版树状图 GET
+ */
+
+export function getSendNumByCompany() {
+  return request({
+    url: `/admin/erp/SmsMailTemplate/getSendNumByCompany`,
+    method: 'get',
+  })
+}
+
+/* 选中的模版 */
+export function updateSelectMsg(parmas) {
+  return request({
+    url: `/admin/erp/SmsMailTemplate/updateSelectMsg`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}

+ 89 - 0
src/api/express.js

@@ -0,0 +1,89 @@
+addExpress/**
+ * 快递公司相关API
+ */
+
+import request from '@/utils/request'
+import qs from 'qs'
+
+/**
+ * 获取物流公司列表
+ * @param params
+ */
+export function getExpressList(params) {
+  return request({
+    url: 'admin/systems/logi-companies',
+    method: 'get',
+    loading: false,
+    params
+  })
+}
+
+/**
+ * 添加物流公司
+ * @param params
+ */
+export function addExpress(params) {
+  let arr = params.formItems
+  delete params.formItems
+  return request({
+    url: `admin/systems/logi-companies?${qs.stringify(params)}`,
+    method: 'post',
+    headers: {
+      'Content-Type': 'application/json'
+    },
+    data: arr
+  })
+}
+
+/**
+ * 删除物流公司
+ * @param id
+ */
+export function deleteExpress(id) {
+  return request({
+    url: `admin/systems/logi-companies/${id}`,
+    method: 'delete'
+  })
+}
+
+/**
+ * 获取物流公司详情
+ * @param id
+ */
+export function getExpressDetail(id) {
+  return request({
+    url: `admin/systems/logi-companies/${id}`,
+    method: 'get'
+  })
+}
+
+/**
+ * 修改物流公司
+ * @param id
+ * @param params
+ */
+export function editExpress(id, params) {
+  let arr = params.formItems
+  delete params.formItems
+  return request({
+    url: `admin/systems/logi-companies/${id}?${qs.stringify(params)}`,
+    method: 'put',
+    headers: {
+      'Content-Type': 'application/json'
+    },
+    data: arr
+  })
+}
+
+/**
+ * 开启或禁用物流公司
+ * @param id
+ * @param status
+ */
+export function openDisableExpress(id, disabled) {
+  return request({
+    url: `admin/systems/logi-companies/${id}`,
+    method: 'post',
+    data: { disabled }
+  })
+}

+ 160 - 0
src/api/goodsInventoryLoss.js

@@ -0,0 +1,160 @@
+/**
+ * 库存报损相关API
+ */
+
+import request from '@/utils/request'
+
+/**
+ * 归还库存报损
+ * @param id
+ * @param parmas
+ */
+export function returnGoodsInventoryLoss(id, parmas) {
+  return request({
+    url: `admin/stock/damage/report/return/${id}`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/**
+ * 批量确认库存报损单
+ * @param id
+ */
+export function InventoryLossFormConfirm(ids) {
+  return request({
+    url: `admin/stock/damage/report/confirm/${ids}`,
+    method: 'post'
+  })
+}
+
+/**
+ * 修改库存报损
+ * @param id
+ * @param parmas
+ */
+export function editgoodsInventoryLossAdd(id, parmas) {
+  return request({
+    url: `admin/stock/damage/report/${id}`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/**
+ * 添加库存报损
+ * @param params
+ */
+export function addgoodsInventoryLossAdd(params) {
+  return request({
+    url: 'admin/stock/damage/report',
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data: params
+  })
+}
+
+/**
+ * 提交审核库存报损单
+ * @param ids
+ */
+export function submitAuditGoodsInventoryLoss(ids) {
+  return request({
+    url: `admin/stock/damage/report/submit/${ids}`,
+    method: 'post'
+  })
+}
+
+/**
+ * 撤回库存报损
+ * @param ids
+ */
+export function cancelGoodsInventoryLoss(ids) {
+  return request({
+    url: `admin/stock/damage/report/cancel/${ids}`,
+    method: 'post'
+  })
+}
+
+/**
+ * 审核库存报损
+ * @param params
+ */
+export function auditGoodsInventoryLoss(ids, parmas) {
+  return request({
+    url: `admin/stock/damage/report/audit/${ids}`,
+    method: 'post',
+    data: parmas
+  })
+}
+
+/**
+ * 获取库存报损详情
+ * @param params
+ */
+export function getGoodsInventoryLossInfo(id) {
+  return request({
+    url: `admin/stock/damage/report/${id}`,
+    method: 'get',
+    loaidng: false
+  })
+}
+
+/**
+ * 获取库存报损列表
+ * @param params
+ */
+export function getGoodsInventoryLossList(params) {
+  return request({
+    url: 'admin/stock/damage/report',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 更新库存报损
+ * @param id
+ * @param parmas
+ */
+export function editGoodsInventoryLoss(id, parmas) {
+  return request({
+    url: `admin/stock/damage/report/${id}`,
+    method: 'put',
+    headers: { 'Content-Type': 'application/json' },
+    data: parmas
+  })
+}
+
+/**
+ * 删除库存报损
+ * @param id
+ */
+export function deleteGoodsInventoryLoss(ids) {
+  return request({
+    url: `admin/stock/damage/report/${ids}`,
+    method: 'delete'
+  })
+}
+
+/* /admin/stock/damage/report/syncStock/{id} */
+export function getSyncStock(ids) {
+  return request({
+    url: `/admin/stock/damage/report/syncStock/${ids}`,
+    method: 'post',
+  })
+}
+
+/* 
+/admin/stock/damage/report/submit/{id} */
+export function submit(id,params) {
+  return request({
+    url: `/admin/stock/damage/report/submit/${id}`,
+    method: 'post',
+    headers: { 'Content-Type': 'application/json' },
+    data:params
+  })
+}

+ 261 - 0
src/api/statistics.js

@@ -0,0 +1,261 @@
+/**
+ * 统计相关API
+ */
+
+import request from '@/utils/request'
+
+/**
+ * 导出库存成本列表
+ * @param params
+ */
+export function getstockCostExport(params) {
+  return request({
+    url: 'admin/stock/statistics/export-cost',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询库存成本统计分页列表数据
+ * @param params
+ */
+export function getstockCostStatistics(params) {
+  return request({
+    url: 'admin/stock/statistics/cost',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出库存列表
+ * @param params
+ */
+export function getstockExport(params) {
+  return request({
+    url: 'admin/stock/statistics/export',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询库存统计分页列表数据
+ * @param params
+ */
+export function getstockStatistics(params) {
+  return request({
+    url: 'admin/stock/statistics',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出采购列表
+ * @param params
+ */
+export function getwarehouseEntryExport(params) {
+  return request({
+    url: 'admin/erp/warehouseEntry/export',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询采购统计分页列表数据
+ * @param params
+ */
+export function getwarehouseEntryStatistics(params) {
+  return request({
+    url: 'admin/erp/warehouseEntry/statistics',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+/**
+ * 获取某商品入库统计
+ * @param {*} params
+ * @returns
+ */
+export function getStockBatchFlow(params) {
+  return request({
+    url: 'admin/erp/stockBatchFlow',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出供应商退货列表
+ * @param params
+ */
+export function getsupplierReturnExport(params) {
+  return request({
+    url: 'admin/erp/supplierReturn/export',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询供应商退货统计分页列表数据
+ * @param params
+ */
+export function getsupplierReturnStatistics(params) {
+  return request({
+    url: 'admin/erp/supplierReturn/statistics',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出出库列表
+ * @param params
+ */
+export function getwarehouseOutExport(params) {
+  return request({
+    url: 'admin/erp/warehouseOut/export',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询出库统计分页列表数据
+ * @param params
+ */
+export function getwarehouseOutStatistics(params) {
+  return request({
+    url: 'admin/erp/warehouseOut/statistics',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出订单退货列表
+ * @param params
+ */
+export function getorderReturnExport(params) {
+  return request({
+    url: 'admin/erp/orderReturn/export',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询订单退货统计分页列表数据
+ * @param params
+ */
+export function getorderReturnStatistics(params) {
+  return request({
+    url: 'admin/erp/orderReturn/statistics',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出调拨列表
+ * @param params
+ */
+export function getStockTransferExport(params) {
+  return request({
+    url: 'admin/erp/stockTransfer/export',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询调拨统计分页列表数据
+ * @param params
+ */
+export function getstockTransferStatistics(params) {
+  return request({
+    url: '/admin/erp/stockTransfer',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出库存调整单商品列表
+ * @param params
+ */
+export function getStockDamageReportExport(params) {
+  return request({
+    url: 'admin/stock/damage/report/export',
+    method: 'get',
+    responseType: 'blob',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 查询库存调整单商品统计分页列表数据
+ * @param params
+ */
+export function getStockDamageReportStatistics(params) {
+  return request({
+    url: 'admin/stock/damage/report/statistics',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}
+
+/**
+ * 导出商品换货单商品列表
+ * @param params
+ */
+export function getChangeFormExport(params) {
+  return request({
+    url: 'admin/change/form/export',
+    method: 'get',
+    loaidng: false,
+    responseType: 'blob',
+    params
+  })
+}
+
+/**
+ * 查询商品换货单商品统计分页列表数据
+ * @param params
+ */
+export function getChangeFormStatistics(params) {
+  return request({
+    url: 'admin/change/form/statistics',
+    method: 'get',
+    loaidng: false,
+    params
+  })
+}

+ 11 - 8
src/components/layout/Header.vue

@@ -191,18 +191,16 @@
                     </div>
                   </li>
                   <li>
-                    <router-link to="/users/profile" class="dark:hover:text-white" @click="close()">
+                    <a href="javascript:;" class="dark:hover:text-white" @click="goInfo">
                       <icon-user class="w-4.5 h-4.5 ltr:mr-2 rtl:ml-2 shrink-0" />
-
                       个人信息
-                    </router-link>
+                    </a>
                   </li>
-
                   <li class="border-t border-white-light dark:border-white-light/10">
-                    <div class="text-danger !py-3" @click="handleLogoutClick">
+                    <a class="text-danger !py-3 dark:hover:text-white" @click="handleLogoutClick">
                       <icon-logout class="w-4.5 h-4.5 ltr:mr-2 rtl:ml-2 rotate-90 shrink-0" />
                       退出
-                    </div>
+                    </a>
                   </li>
                 </ul>
               </template>
@@ -351,7 +349,12 @@ const setActiveDropdown = () => {
     }
   }
 };
-
+/* 前往个人信息页面 */
+const goInfo=()=>{
+  router.push({
+    name:""
+  })
+}
 const removeNotification = (value: number) => {
   notifications.value = notifications.value.filter((d) => d.id !== value);
 };
@@ -366,7 +369,7 @@ const toggleSidebars = () => {
 const toggleTheme = (theme) => {
   store.dispatch('toggleTheme', theme);
 };
-const close = () => {
+const closes = () => {
   console.log('001');
 };
 const handleLogoutClick = () => {

+ 13 - 4
src/components/layout/Sidebar.vue

@@ -29,7 +29,7 @@
           class="h-[calc(100vh-80px)] relative"
         >
           <ul class="relative font-semibold space-y-0.5 p-4 py-0">
-            <li class="menu nav-item">
+            <!-- <li class="menu nav-item">
               <button
                 type="button"
                 class="nav-link group w-full"
@@ -65,7 +65,7 @@
                   </li>
                 </ul>
               </vue-collapsible>
-            </li>
+            </li> -->
             <li class="menu nav-item">
               <button
                 type="button"
@@ -220,10 +220,16 @@
                   <li>
                     <router-link to="/stock/goodsOutBound" @click="toggleMobileMenu">{{ $t('goodsOutBound') }}</router-link>
                   </li>
-                  <!-- goodsInventory -->
+                  <!-- goodsUnderstock -->
                   <li>
                     <router-link to="/stock/goodsInventory" @click="toggleMobileMenu">{{ $t('goodsInventory') }}</router-link>
                   </li>
+                  <li>
+                    <router-link to="/stock/goodsInventoryLoss" @click="toggleMobileMenu">{{ $t('goodsInventoryLoss') }}</router-link>
+                  </li>
+                  <li>
+                    <router-link to="/stock/goodsUnderstock" @click="toggleMobileMenu">{{ $t('goodsUnderstock') }}</router-link>
+                  </li>
                 </ul>
               </vue-collapsible>
             </li>
@@ -257,8 +263,11 @@
                   <li>
                     <router-link to="/companyMent/companyInfo" @click="toggleMobileMenu">{{ $t('companyInfo') }}</router-link>
                   </li>
+                  <li>
+                    <router-link to="/companyMent/configMsg" @click="toggleMobileMenu">{{ $t('configMsg') }}</router-link>
+                  </li>
                 </ul>
-                <!-- companyInfo -->
+                <!-- configMsg -->
               </vue-collapsible>
               <vue-collapsible :isOpen="activeDropdown === 'companyMent'">
                 <ul class="sub-menu text-gray-500"></ul>

+ 2 - 0
src/locales/zh.json

@@ -6,6 +6,8 @@
     "goodsExchange":"入库管理",
     "goodsOutBound":"出库管理",
     "goodsInventory":"库存盘点",
+    "goodsInventoryLoss":"库存报损",
+    "goodsUnderstock":"调拨列表",
        
     "setting":"系统管理",
     "companyList":"公司列表",

+ 5 - 1
src/router/index.ts

@@ -36,11 +36,14 @@ const asyncRouterMap: RouteRecordRaw[] = [
             { path: 'goodsExchange', component: () => import('@/views/stock/warehousing.vue'), name: 'goodsExchange', meta: { title: 'goodsExchange' } },
             { path: 'goodsOutBound', component: () => import('@/views/stock/outbound.vue'), name: 'goodsOutBound', meta: { title: 'goodsOutBound' } },
             { path: 'warehouseLocation', component: () => import('@/views/stock/warehouseLocation.vue'), name: 'warehouseLocation', meta: { title: 'warehouseLocation' ,layout: 'app'} },
-            /* addOutbound */
             { path: 'addInventory', component: () => import('@/views/stock/addInventory.vue'), name: 'addInventory', meta: { title: 'addInventory' ,layout: 'app'} },
             { path: 'addOutbound', component: () => import('@/views/stock/addOutbound.vue'), name: 'addOutbound', meta: { title: 'addOutbound' ,layout: 'app'} },
             { path: 'goodsInventory', component: () => import('@/views/stock/goodsInventory.vue'), name: 'goodsInventory', meta: { title: 'goodsInventory' ,layout: 'app'} },
             { path: 'goodsInventoryAdd', component: () => import('@/views/stock/goodsInventoryAdd.vue'), name: 'goodsInventoryAdd', meta: { title: 'goodsInventoryAdd' ,layout: 'app'} },
+            { path: 'goodsInventoryLoss', component: () => import('@/views/stock/goodsInventoryLoss.vue'), name: 'goodsInventoryLoss', meta: { title: 'goodsInventoryLoss' ,layout: 'app'} },
+            { path: 'goodsInventoryLossAdd', component: () => import('@/views/stock/goodsInventoryLossAdd.vue'), name: 'goodsInventoryLossAdd', meta: { title: 'goodsInventoryLossAdd' ,layout: 'app'} },
+            { path: 'goodsUnderstock', component: () => import('@/views/stock/goodsUnderstock.vue'), name: 'goodsUnderstock', meta: { title: 'goodsUnderstock' ,layout: 'app'} },
+            { path: 'goodsUnderstockAdd', component: () => import('@/views/stock/goodsUnderstockAdd.vue'), name: 'goodsUnderstockAdd', meta: { title: 'goodsUnderstockAdd' ,layout: 'app'} },
         ]
     },
     {
@@ -90,6 +93,7 @@ const asyncRouterMap: RouteRecordRaw[] = [
             { path: 'administratorManage', component: () => import('@/views/companyMent/administratorManage.vue'), name: 'administratorManage', meta: { title: 'administratorManage', layout: 'app' } },
             { path: 'branch', component: () => import('@/views/companyMent/branch.vue'), name: 'branch', meta: { title: 'branch', layout: 'app' } },
            { path: 'companyInfo', component: () => import('@/views/companyMent/companyInfo.vue'), name: 'companyInfo', meta: { title: 'companyInfo', layout: 'app' } },
+           { path: 'configMsg', component: () => import('@/views/companyMent/configMsg.vue'), name: 'configMsg', meta: { title: 'configMsg', layout: 'app' } },
         ]
     },
     {

+ 8 - 4
src/views/companyMent/administratorManage.vue

@@ -84,11 +84,11 @@
       :close-on-press-escape="false"
     >
       <el-form :model="adminForm" :rules="adminRules" ref="adminFormRef" label-width="120px">
-        <el-form-item label="用户姓名" prop="real_name">
-          <el-input v-model="adminForm.real_name" :minlength="2" :maxlength="20" clearable placeholder="请输入用户姓名"></el-input>
+        <el-form-item label="手机号" prop="phone">
+          <el-input v-model="adminForm.phone" :minlength="2" :maxlength="20" clearable placeholder="请输入手机号"></el-input>
         </el-form-item>
-        <el-form-item label="用户编码" prop="sn">
-          <el-input v-model="adminForm.sn" :maxlength="20" clearable placeholder="请输入用户编码"></el-input>
+        <el-form-item label="邮箱" prop="email">
+          <el-input v-model="adminForm.email" :maxlength="20" clearable placeholder="请输入邮箱"></el-input>
         </el-form-item>
         <el-form-item label="昵称" prop="nickname">
           <el-input v-model="adminForm.nickname" :maxlength="20" clearable placeholder="请输入昵称"></el-input>
@@ -168,6 +168,8 @@ const adminForm = reactive({
   id: '',
   role_id: '',
   face: '',
+  phone:"",
+  email:""
 });
 const adminFormRef = ref();
 const advancedForm = reactive({
@@ -202,6 +204,8 @@ const adminRules = reactive({
   department: [{ required: true, message: '请输入所属部门!' }],
   role_id: [{ required: true, message: '请选择所属角色!', trigger: 'change' }],
   face: [{ required: true, message: '请上传人员头像!' }],
+  phone: [{ required: true, message: '请输入手机号!' }],
+  email: [{ required: true, message: '请输入邮箱!' }],
 });
 const dialogVisible = ref(false);
 const rolesOptions = ref([]);

+ 518 - 0
src/views/companyMent/configMsg.vue

@@ -0,0 +1,518 @@
+<template>
+  <div class="permission-container">
+    <el-form :model="configMsgForm" :rules="permissionRules" ref="configMsgFormRef" label-width="200px" class="demo-ruleForm">
+      <el-form-item label="消息配置" prop="permission">
+        <!-- <el-checkbox :indeterminate="allIndeterminate" v-model="allCheck" @change="handleCheckAll">全部选择</el-checkbox> -->
+        <div v-for="item in permissions" :key="item.identifier" class="level_1">
+          <el-row :gutter="20">
+            <el-col :span="4">
+              <el-checkbox
+                v-model="item.has_select"
+                :label="item.name"
+                :indeterminate="checkIndeterminate(item.children)"
+                @change="handleCheckboxChanged(item)"
+              ></el-checkbox>
+            </el-col>
+            <el-col :span="20">
+              <div v-for="_item in item.child" :key="_item.identifier" class="checkbox-dropdown">
+                <el-popover placement="bottom" trigger="hover" :open-delay="300" :disabled="!hasChildren(_item)" :append-to-body="false">
+                  <template #reference>
+                    <el-checkbox
+                      v-model="_item.has_select"
+                      :indeterminate="checkIndeterminate(_item.child)"
+                      @click.stop
+                      @change="handleCheckboxChanged(_item, item)"
+                    >
+                      {{ _item.name }}
+                      <template v-if="hasChildren(_item)">
+                        <i class="el-icon-arrow-down"></i>
+                      </template>
+                    </el-checkbox>
+                  </template>
+                  <div class="role-dropdown__list" v-if="hasChildren(_item)">
+                    <div class="role-dropdown" v-for="__item in _item.child" :key="__item.identifier">
+                      <el-popover placement="right" trigger="hover" :open-delay="200" :disabled="!hasChildren(__item)" :append-to-body="false">
+                        <template #reference>
+                          <div class="role-dropdown__label">
+                            <el-checkbox
+                              v-model="__item.has_select"
+                              :indeterminate="checkIndeterminate(__item.child)"
+                              @click.stop
+                              @change="handleCheckboxChanged(__item, _item)"
+                            >
+                              {{ __item.name }}
+                              <template v-if="hasChildren(__item)">
+                                <i class="el-icon-arrow-right"></i>
+                              </template>
+                            </el-checkbox>
+                          </div>
+                        </template>
+                        <div class="role-dropdown__list" v-if="hasChildren(__item)">
+                          <div class="role-dropdown" v-for="___item in __item.child" :key="___item.identifier">
+                            <el-popover placement="right" trigger="hover" :open-delay="200" :disabled="!hasChildren(___item)" :append-to-body="false">
+                              <template #reference>
+                                <div class="role-dropdown__label">
+                                  <el-checkbox
+                                    v-model="___item.has_select"
+                                    :indeterminate="checkIndeterminate(___item.child)"
+                                    @click.stop
+                                    @change="handleCheckboxChanged(___item, __item)"
+                                    >{{ ___item.name }}</el-checkbox
+                                  >
+                                </div>
+                              </template>
+                            </el-popover>
+                          </div>
+                        </div>
+                      </el-popover>
+                    </div>
+                  </div>
+                </el-popover>
+              </div>
+            </el-col>
+          </el-row>
+        </div>
+      </el-form-item>
+      <el-form-item label="">
+        <el-button type="primary" size="small" style="margin-top: 15px" @click="saveRolePermission">保存设置</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+      
+      <script lang="ts" setup>
+import { ref, reactive, onMounted, watch, nextTick } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import * as API_Auth from '@/api/auth';
+import * as API_Menus from '@/api/menus';
+import * as API_Setting from '@/api/setting';
+import * as API_Company from '@/api/company';
+/*   import { Foundation } from '../../composables/ui-utils'; */
+
+const route = useRoute();
+const router = useRouter();
+
+const props = {
+  label: 'name',
+  value: 'id',
+  emitPath: false,
+  multiple: true,
+  checkStrictly: true,
+};
+
+const checked = ref(true);
+const deptList = ref<any>([]);
+const oneDimensionalList = ref<any>([]); // 源数据平铺成一级节点
+
+/** 权限 表单 */
+const configMsgForm = reactive({
+  data_scope: 'ALL',
+  role_name: '',
+  role_describe: '',
+});
+
+/** 权限 表单规则 */
+const permissionRules = reactive({
+  role_name: [
+    { required: true, message: '请输入角色名称!', trigger: 'blur' },
+    { min: 1, max: 10, message: '长度在 1 到 10 个字符', trigger: 'blur' },
+  ],
+});
+
+const permissions = ref<any>([]);
+const allCheck = ref(false);
+const allIndeterminate = ref(false);
+const isAllSelected = ref(false);
+
+const role_id = ref<any>(route.query.id);
+const searchSelectAllNodeIndex = () => {
+  let selectAllOptionIndex = -1;
+  configMsgForm.dept_ids.forEach((res, index) => {
+    if (res.length === 1) {
+      selectAllOptionIndex = index;
+    }
+  });
+  return selectAllOptionIndex;
+};
+
+const visibleChange = (visible) => {
+  if (visible) {
+    deptList.value.unshift({
+      id: '全选',
+      name: '全选',
+      value: '全选',
+    });
+  } else {
+    deptList.value.shift();
+  }
+};
+
+// 选择级联选择器
+const selectHandle = async (e = []) => {
+  const selectLength = e.filter((v) => v !== '全选').length;
+  const has_all_option = e.some((v) => v === '全选');
+  let dept_ids = [...configMsgForm.dept_ids];
+
+  if (has_all_option && isAllSelected.value) {
+    // 移除了选项中除全部外的某个节点
+    dept_ids = dept_ids.filter((v) => v !== '全选');
+    dept_ids.splice(searchSelectAllNodeIndex(), 1);
+    configMsgForm.dept_ids = dept_ids;
+    isAllSelected.value = false;
+  } else if (has_all_option && !isAllSelected.value) {
+    // 选中全部节点
+    isAllSelected.value = true;
+    const deptListData = deptList.value;
+    const dept_ids = [];
+    const loopSelectData = (list) => {
+      list.forEach((e) => {
+        dept_ids.push(e.id);
+        if (e.children && e.children.length > 0) {
+          loopSelectData(e.children);
+        }
+      });
+    };
+    loopSelectData(deptListData);
+    configMsgForm.dept_ids = dept_ids;
+  } else if (!has_all_option && isAllSelected.value) {
+    // 取消选中全部节点
+    isAllSelected.value = false;
+    configMsgForm.dept_ids = [];
+  } else if (selectLength === oneDimensionalList.value.length) {
+    isAllSelected.value = true;
+    dept_ids.unshift('全选');
+    configMsgForm.dept_ids = dept_ids;
+  }
+  nextTick(() => {
+    // 强制更新
+  });
+};
+/* 处理树形数据 */
+let buildTree = function buildTree(list, parent_id) {
+  const tree = [];
+  for (let i = 0; i < list.length; i++) {
+    if (list[i].parent_id === parent_id) {
+      const node = {
+        id: list[i].id,
+        parent_id: list[i].parent_id,
+        name: list[i].name,
+        create_time: list[i].create_time,
+        remark: list[i].remark,
+        sn: list[i].sn,
+        sort: list[i].sort,
+        type: list[i].type,
+        region_ids: list[i].region_ids,
+        children: buildTree(list, list[i].id),
+      };
+      tree.push(node);
+    }
+  }
+  return tree;
+};
+/** 获取部门 */
+const GET_DeptList = () => {
+  API_Setting.getDeptList().then((response) => {
+    deptList.value = buildTree(response, '0');
+    const oneDimensionalListData = [];
+    const loopData = (list) => {
+      list.forEach((e) => {
+        oneDimensionalListData.push(e);
+        if (e.children && e.children.length > 0) {
+          loopData(e.children);
+        }
+      });
+    };
+    loopData(response);
+    oneDimensionalList.value = oneDimensionalListData;
+    if (configMsgForm.dept_ids.length === oneDimensionalListData.length) {
+      // 设置数据范围全选
+      configMsgForm.dept_ids.push('全选');
+      isAllSelected.value = true;
+    }
+  });
+};
+
+/** 判断是否还有子集 */
+const hasChildren = (item) => {
+  return Array.isArray(item.children) && item.children.length !== 0;
+};
+
+/** 全选 */
+const handleCheckAll = (checked) => {
+  allIndeterminate.value = false;
+  permissions.value = setPermissionsCheck(permissions.value, checked);
+};
+
+/** 选择 */
+const handleCheckboxChanged = (item, parent) => {
+  if (item.child && item.child.length) {
+    item.child = setPermissionsCheck(item.child, item.checked);
+  }
+  /*   countAllPermissions(permissions.value);
+  countParentChecked(permissions.value); */
+};
+
+/** 设置权限状态 */
+const setPermissionsCheck = (permissions, checked) => {
+  const perm = [...permissions];
+  perm.map((item) => {
+    item.checked = checked;
+    if (item.children && item.children.length) {
+      item.children = setPermissionsCheck(item.children, checked);
+    }
+  });
+  return perm;
+};
+
+/** 检测是否有不确定性 */
+const checkIndeterminate = (permissions) => {
+  if (!Array.isArray(permissions)) return false;
+  const _len = permissions.length;
+  const __len = permissions.filter((item) => item.checked).length;
+  return __len !== 0 && _len !== __len;
+};
+
+/** 获取所有权限展开后的长度、被选中的长度 */
+const countAllPermissions = (perms?: any[]) => {
+  const currentPermissions = perms || permissions.value;
+  if (!Array.isArray(currentPermissions)) {
+    console.warn('permissions is not an array:', currentPermissions);
+    return [];
+  }
+  const _list = [];
+  currentPermissions.forEach((item) => {
+    _list.push(item);
+    if (item.children) _list.push(...countAllPermissions(item.children));
+  });
+  const length = _list.length;
+  const length_checked = _list.filter((_item) => _item.checked).length;
+  allCheck.value = length === length_checked;
+  allIndeterminate.value = length_checked !== 0 && length !== length_checked;
+  return _list;
+};
+
+/** 计算所有父辈的选中状态 */
+const countParentChecked = (perms?: any[]) => {
+  const currentPermissions = perms || permissions.value;
+  currentPermissions.forEach((item) => {
+    if (item.children && item.children.length) {
+      countParentChecked(item.children);
+      const length = item.children.length;
+      const checked_length = item.children.filter((_item) => _item.checked).length;
+      item.checked = !!checked_length;
+    }
+  });
+};
+
+/** 保存角色权限 */
+const configMsgFormRef = ref();
+const saveRolePermission = () => {
+  configMsgFormRef.value.validate((valid) => {
+    if (valid) {
+      let params = { vos: permissions.value };
+      /*  if (!params.dept_ids) {
+        ElMessage.error('请选择数据范围!');
+        return;
+      }
+      params.dept_ids = params.dept_ids.filter((v) => v !== '全选');
+      if (params.dept_ids) {
+        if (isAllSelected.value) {
+          params.data_scope = 'ALL';
+          params.dept_ids = params.dept_ids.join(',');
+        } else {
+          params.data_scope = 'DEPT_CUSTOM';
+          params.dept_ids = params.dept_ids.join(',');
+        }
+      } */
+      API_Company.updateSelectMsg(params).then((res) => {
+        ElMessage.success('保存成功!');
+        GET_RolePermission()
+      });
+      /* const saveSuccess = () => {
+        ElMessage.success('保存成功!');
+         router.push({ name: 'roleManage' }); 
+      };*/
+      /*  role_id.value === '0' ? API_Auth.addRole(params).then(() => saveSuccess()) : API_Auth.editRole(role_id.value, params).then(() => saveSuccess()); */
+    } else {
+      ElMessage.error('表单填写有误,请检查!');
+      return false;
+    }
+  });
+};
+
+/** 获取消息树 */
+const GET_RolePermission = () => {
+  API_Company.getSendNumByCompany().then((res) => {
+    permissions.value = res;
+  });
+  /*  API_Menus.getMenusChildren().then((res) => {
+      if (role_id.value !== '0') {
+        API_Auth.getRolePermission(role_id.value).then((response) => {
+          const checkedIds = expandRouters(response.menus);
+          permissions.value = filterRoleRouter(res, checkedIds);
+          if (Array.isArray(permissions.value)) {
+            countAllPermissions();
+          } else {
+            console.warn('Invalid permissions data:', permissions.value);
+          }
+          GET_DeptList();
+        });
+      } else {
+        permissions.value = res;
+        if (Array.isArray(permissions.value)) {
+          countAllPermissions();
+        } else {
+          console.warn('Invalid permissions data:', permissions.value);
+        }
+        GET_DeptList();
+      } 
+    });*/
+};
+
+/** 展开路由的identifier */
+const expandRouters = (menus) => {
+  const routers = [];
+  menus.forEach((item) => {
+    item.checked && routers.push(item.identifier);
+    if (item.children && item.children.length) {
+      routers.push(...expandRouters(item.children));
+    }
+  });
+  return routers;
+};
+
+/** 递归筛选被选中的路由 */
+const filterRoleRouter = (routers, ids) => {
+  const _routers = [];
+  routers.forEach((item) => {
+    if (ids.includes(item.identifier) || item.hidden) {
+      item.checked = true;
+    } else {
+      item.checked = false;
+    }
+    if (item.children) {
+      item.children = filterRoleRouter(item.children, ids);
+    }
+    _routers.push(item);
+  });
+  return _routers;
+};
+
+onMounted(() => {
+  GET_RolePermission();
+});
+
+/* watch(
+  () => route.query.id,
+  () => {
+    role_id.value = route.query.id;
+    GET_RolePermission();
+  }
+); */
+</script>
+      
+    <style scoped>
+.permission-container {
+  padding: 10px;
+  background-color: #fff;
+  padding-bottom: 150px;
+}
+
+.level_1 {
+  padding: 15px 0;
+  border-bottom: 1px dashed #e7e7e7;
+}
+
+.level_1:last-child {
+  border-bottom: none;
+}
+
+::v-deep .el-form-item__label {
+  padding-top: 15px;
+}
+
+::v-deep .el-form-item__content {
+  display: block;
+  border-left: 1px solid #e7e7e7;
+  padding-left: 20px;
+  padding-top: 15px;
+}
+
+::v-deep .el-form-item__content .el-form-item__error {
+  padding-left: 20px;
+}
+
+::v-deep .el-form-item:last-child .el-form-item__content {
+  padding-top: 0;
+}
+
+::v-deep .el-form-item:not(:first-child) {
+  border-top: 1px solid #e7e7e7;
+  position: relative;
+}
+
+::v-deep .el-form-item:not(:first-child)::after {
+  content: ' ';
+  width: 1px;
+  height: 22px;
+  background-color: #e7e7e7;
+  position: absolute;
+  top: -22px;
+  left: 200px;
+}
+
+::v-deep .el-button-group {
+  display: inline-block;
+}
+
+::v-deep .el-button-group .el-button {
+  display: inline-block;
+  padding: 0;
+  border: none;
+}
+
+::v-deep .el-button-group .el-button:focus,
+::v-deep .el-button-group .el-button:hover {
+  color: #606266;
+  border-color: #fff;
+  background-color: #fff;
+}
+
+.checkbox-dropdown {
+  display: inline-block;
+  min-width: 130px;
+  cursor: pointer;
+}
+
+.checkbox-dropdown .checked {
+  color: #409eff;
+}
+
+.role-dropdown {
+  display: flex;
+  align-items: center;
+  width: 25%;
+  height: 30px;
+  margin-bottom: 10px;
+}
+
+.role-dropdown:last-child {
+  margin-bottom: 0;
+}
+
+.role-dropdown__label {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+
+::v-deep .role-dropdown__label .el-checkbox__label {
+  color: inherit;
+}
+
+.role-dropdown__list {
+  max-height: 320px;
+  overflow-y: auto;
+}
+</style>

+ 120 - 39
src/views/setting/companyList.vue

@@ -26,7 +26,7 @@
 
         <el-table-column label="操作">
           <template #default="scope">
-            <el-button size="mini" v-if="checkPermission(['warehouse:update'])" @click="getBranch('compan')">查看</el-button>
+            <!-- <el-button size="mini" v-if="checkPermission(['warehouse:update'])" @click="getBranch('compan')">查看</el-button> -->
             <el-button size="mini" v-if="checkPermission(['warehouse:update'])" @click="handleEditWarehouse(scope.$index, scope.row)">编辑</el-button>
             <el-button size="mini" v-if="checkPermission(['warehouse:update'])" @click="handleRenew(scope.$index, scope.row)">续费</el-button>
             <el-button size="mini" class="mt-1" v-if="checkPermission(['warehouse:update'])" @click="handleBranch(scope.$index, scope.row)">部门管理</el-button>
@@ -58,6 +58,50 @@
     >
       <el-form :model="companyForm" :rules="stockRules" ref="companyFormRef" label-width="140px">
         <el-row>
+          <el-col :span="16">
+            <el-form-item label="营业执照:" prop="license">
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :show-file-list="false"
+                :on-success="handleAvatarSuccess"
+                :before-upload="beforeAvatarUpload"
+              >
+                <img v-if="companyForm.license" :src="companyForm.license" class="avatar w-28 h-28" />
+                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
+              </el-upload>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item label="身份证正面:" prop="id_card_front">
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :show-file-list="false"
+                :on-success="handleFrontSuccess"
+                :before-upload="beforeFrontUpload"
+              >
+                <img v-if="companyForm.id_card_front" :src="companyForm.id_card_front" class="avatar w-28 h-28" />
+                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
+              </el-upload>
+             <!--  <p>姓名:{{ companyForm.value.id_card_front.name }}</p>
+              <p>身份证号码:{{ companyForm.value.id_card_front.id_card_number }}</p> -->
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item label="身份证反面:" prop="id_card_opposite">
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadUrl"
+                :show-file-list="false"
+                :on-success="handleOppositeSuccess"
+                :before-upload="beforeOppositeUpload"
+              >
+                <img v-if="companyForm.id_card_opposite" :src="companyForm.id_card_opposite" class="avatar w-28 h-28" />
+                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
+              </el-upload>
+            </el-form-item>
+          </el-col>
           <el-col :span="10" v-if="!companyForm.id">
             <el-form-item label="套餐:" prop="company_package_id">
               <el-select v-model="companyForm.company_package_id" clearable placeholder="请选择套餐">
@@ -67,43 +111,43 @@
           </el-col>
           <el-col :span="10">
             <el-form-item label="公司名称:" prop="name">
-              <el-input v-model="companyForm.name" :minlength="2" :maxlength="20" clearable placeholder="请输入公司名称"></el-input>
+              <el-input v-model="companyForm.name" clearable disabled placeholder="请输入公司名称"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
             <el-form-item label="统一社会信用代码:" prop="credit_code">
-              <el-input v-model="companyForm.credit_code" :minlength="2" :maxlength="20" clearable placeholder="请输入统一社会信用代码"></el-input>
+              <el-input v-model="companyForm.credit_code" clearable disabled placeholder="请输入统一社会信用代码"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
             <el-form-item label="行业:" prop="industry">
-              <el-input v-model="companyForm.industry" :minlength="2" :maxlength="20" clearable placeholder="请输入行业"></el-input>
+              <el-input v-model="companyForm.industry" clearable placeholder="请输入行业"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
-            <el-form-item label="联系人:" prop="user_name">
-              <el-input v-model="companyForm.user_name" :minlength="2" :maxlength="20" clearable placeholder="请输入联系人"></el-input>
+            <el-form-item label="人:" prop="user_name">
+              <el-input v-model="companyForm.user_name" disabled clearable placeholder="请输入联系人"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
-            <el-form-item label="联系人电话:" prop="phone">
-              <el-input v-model="companyForm.phone" :minlength="2" :maxlength="20" clearable placeholder="请输入联系人电话"></el-input>
+            <el-form-item label="人电话:" prop="phone">
+              <el-input v-model="companyForm.phone" clearable placeholder="请输入联系人电话"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
             <el-form-item label="邮箱:" prop="email">
-              <el-input v-model="companyForm.email" :minlength="2" :maxlength="20" clearable placeholder="请输入邮箱"></el-input>
+              <el-input v-model="companyForm.email" clearable placeholder="请输入邮箱"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
             <el-form-item label="邮编:" prop="postal_code">
-              <el-input v-model="companyForm.postal_code" :minlength="2" :maxlength="20" clearable placeholder="请输入邮箱"></el-input>
+              <el-input v-model="companyForm.postal_code" clearable placeholder="请输入邮箱"></el-input>
             </el-form-item>
           </el-col>
 
           <el-col :span="10">
             <el-form-item label="官网:" prop="website">
-              <el-input v-model="companyForm.website" :minlength="2" :maxlength="20" clearable placeholder="请输入官网地址"></el-input>
+              <el-input v-model="companyForm.website" clearable placeholder="请输入官网地址"></el-input>
             </el-form-item>
           </el-col>
           <el-col :span="10">
@@ -114,20 +158,6 @@
               </span>
             </el-form-item>
           </el-col>
-          <el-col :span="10">
-            <el-form-item label="营业执照:" prop="license">
-              <el-upload
-                class="avatar-uploader"
-                action="http://192.168.8.101:9998/uploaders"
-                :show-file-list="false"
-                :on-success="handleAvatarSuccess"
-                :before-upload="beforeAvatarUpload"
-              >
-                <img v-if="companyForm.license" :src="companyForm.license" class="avatar w-28 h-28" />
-                <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
-              </el-upload>
-            </el-form-item>
-          </el-col>
         </el-row>
       </el-form>
       <template #footer>
@@ -168,10 +198,14 @@ import router from '@/router';
 import { provinceAndCityData, pcTextArr, regionData, pcaTextArr, codeToText } from 'element-china-area-data';
 import { Plus } from '@element-plus/icons-vue';
 import type { UploadProps } from 'element-plus';
-
+/* 营业执照 */
 const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
-  console.log(response, uploadFile);
-  companyForm.value.license = response.url; //URL.createObjectURL(uploadFile.raw!);
+  API_Company.checkLicense({ image_url: response.url }).then((res) => {
+    companyForm.value.name = res.enterprise_name;
+    companyForm.value.credit_code = res.credit_code;
+    companyForm.value.license_msg = res;
+    companyForm.value.license = response.url;
+  });
 };
 
 const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
@@ -181,7 +215,39 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
   }
   return true;
 };
+/* 身份证正面 */
+const handleFrontSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
+  API_Company.checkIdCardOpposite({ image_url: response.url }, 'front').then((res) => {
+    companyForm.value.user_name = res.name;
+    companyForm.value.id_card_msg_front = res;
+    companyForm.value.id_card_front = response.url;
+  });
+};
+
+const beforeFrontUpload: UploadProps['beforeUpload'] = (rawFile) => {
+  if (rawFile.size / 1024 / 1024 > 10) {
+    ElMessage.error('Avatar picture size can not exceed 10MB!');
+    return false;
+  }
+  return true;
+};
+/* 身份证反面 */
+const handleOppositeSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
+  API_Company.checkIdCardOpposite({ image_url: response.url }, 'opposite').then((res) => {
+    companyForm.value.id_card_msg_opposite = res;
+    companyForm.value.id_card_opposite = response.url;
+  });
+};
 
+const beforeOppositeUpload: UploadProps['beforeUpload'] = (rawFile) => {
+  if (rawFile.size / 1024 / 1024 > 10) {
+    ElMessage.error('Avatar picture size can not exceed 10MB!');
+    return false;
+  }
+  return true;
+};
+
+const uploadUrl = ref(import.meta.env.VITE_API_URL + '/uploaders');
 const store = useStore();
 const tableData = ref<any>({});
 const loading = ref(false);
@@ -196,6 +262,11 @@ const companyForm = ref<any>({
   address: '',
   license: '',
   company_package_id: '',
+  license_msg: {},
+  id_card_front: '',
+  id_card_msg_front: {},
+  id_card_opposite: '',
+  id_card_msg_opposite: {},
 });
 const stockRules = ref<any>({
   role_id: [{ required: true, message: '请选择权限!', trigger: 'change' }],
@@ -237,26 +308,26 @@ let packageId = ref('');
 let companyId = ref('');
 const packageFormRef = ref();
 
-const handleBranch=(index: number, row: any)=>{
+const handleBranch = (index: number, row: any) => {
   router.push({ name: 'branch' });
-}
+};
 
 /* 续费 */
 const handleRenew = (index: number, row: any) => {
   packageForm.value.company_package_id = row.company_package_id;
-  companyId.value=row.id
+  companyId.value = row.id;
   packageId.value = row.company_package_id;
   API_Company.companyPackage(row.company_package_id).then((res) => {
     packageForm.value.this_money = res.money;
     renewVisible.value = true;
   });
 };
-const submitPackageForm = () => { 
+const submitPackageForm = () => {
   packageFormRef.value.validate((valid: boolean) => {
     if (valid) {
       API_Company.difference(packageId.value).then((response) => {
         packageForm.value.this_money += response;
-        API_Company.renewCompany(companyId.value,packageId.value).then((res) => {
+        API_Company.renewCompany(companyId.value, packageId.value).then((res) => {
           packageForm.value = {};
           packageId.value = '';
           if (packageId.value == packageForm.value.company_package_id) {
@@ -327,10 +398,20 @@ const submitWarehouseForm = () => {
           GET_CompanyList();
         });
       } else {
-        API_Company.addCompany(params).then(() => {
+        API_Company.addCompany(params).then((res) => {
           dialogVisible.value = false;
-          ElMessage.success('添加成功!');
-          GET_CompanyList();
+          ElMessageBox.confirm(`此为登录密码,请详细记录:${res}`, '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          })
+            .then(() => {
+              GET_CompanyList();
+            })
+            .catch(() => {
+              /* Handle cancel action if needed */
+            });
+        /* ElMessage.success('添加成功!'); */
         });
       }
     } else {
@@ -386,9 +467,9 @@ const adminName = (val: string[]) => {
 
 /* 切换菜单 */
 
-const getBranch=(value)=>{
-  store.dispatch('toggleSuperMenu',value);
-}
+const getBranch = (value) => {
+  store.dispatch('toggleSuperMenu', value);
+};
 
 onMounted(() => {
   GET_CompanyList();

+ 29 - 16
src/views/stock/goodsInventoryAdd.vue

@@ -2,7 +2,7 @@
   <div class="bg-in-stock" v-loading="loading">
     <el-form ref="goodsInventoryAddFormRef" :model="goodsInventoryAddForm" :rules="goodsInventoryAddFormRule" label-width="120px" inline class="change-form">
       <h3 style="width: 100%">盘点单</h3>
-      <el-form-item label="盘点编号" prop="sn" v-if="type === 'edit' || type === 'detail'" class="change-form-item">
+      <el-form-item label="盘点编号" prop="sn" v-if="type === 'edit' || type === 'view'" class="change-form-item">
         <el-input v-model="goodsInventoryAddForm.sn" :disabled="true"></el-input>
       </el-form-item>
       <el-form-item label="盘点时间" prop="inventory_time" class="change-form-item">
@@ -66,7 +66,8 @@
         <el-switch v-model="goodsInventoryAddForm.has_notice" inline-prompt :active-text="true" :inactive-text="false" />
       </el-form-item>
       <el-form-item label="审核人:" prop="notice_user_id" class="change-form-item" v-if="goodsInventoryAddForm.has_notice">
-        <el-select v-model="goodsInventoryAddForm.notice_user_id" :disabled="type === 'detail' || type === 'audit' || type === 'check'">
+        <span v-if="id && type !== 'edit'">{{ getNotice(goodsInventoryAddForm.notice_user_id) }}</span>
+        <el-select v-else v-model="goodsInventoryAddForm.notice_user_id" :disabled="type === 'detail' || type === 'audit' || type === 'check'">
           <el-option v-for="item in auditList" :key="item.id" :label="item.nickname" :value="item.id" />
         </el-select>
       </el-form-item>
@@ -99,7 +100,12 @@
                   <div>
                     <p v-for="item in scope.row.area_stock_list" :key="item.id">{{ item.warehouse_area_name }}</p>
                   </div>
-                  <span slot="reference" v-if="scope.row.area_stock_list.length !== 0">{{ scope.row.area_stock_list[0].warehouse_area_name }}</span>
+                  <template v-slot:reference>
+                    <span v-if="scope.row.area_stock_list.length !== 0">
+                      {{ scope.row.area_stock_list[0].warehouse_area_name }}
+                    </span>
+                  </template>
+                 <!--  <span slot="reference" v-if="scope.row.area_stock_list.length !== 0">{{ scope.row.area_stock_list[0].warehouse_area_name }}</span> -->
                 </el-popover>
               </template>
             </el-table-column>
@@ -177,10 +183,10 @@
     <el-dialog title="扫码入库" v-model="scanDialogVisible" width="30%" :close-on-click-modal="false">
       <el-form ref="scanGoodsForm" :model="scanGoodsForm" label-width="120px" inline>
         <el-form-item label="sku" prop="bar_code">
-          <el-input v-model="scanGoodsForm.bar_code" ref="input" @keyup.enter.native="toSearch()" :minlength="0" :maxlength="100"></el-input>
+          <el-input v-model="scanGoodsForm.bar_code" ref="input" @keyup.enter="toSearch()" :minlength="0" :maxlength="100"></el-input>
         </el-form-item>
         <el-form-item label="序列号" prop="sn_code">
-          <el-input ref="sn_input" v-model="sn_code" @keyup.enter.native="toSnCode()" :minlength="0" :maxlength="100"></el-input>
+          <el-input ref="sn_input" v-model="sn_code" @keyup.enter="toSnCode()" :minlength="0" :maxlength="100"></el-input>
         </el-form-item>
       </el-form>
     </el-dialog>
@@ -268,7 +274,7 @@ const goodsInventoryAddFormRule = ref({
   creator_id: { required: true, message: '请选择制单人', trigger: 'change' },
 });
 const warehouseProduct = ref(null);
-const typeList = ref([]);
+const typeList = ref<any>([]);
 const scanDialogVisible = ref(false);
 const scanGoodsForm = ref<any>({});
 const sn_code = ref('');
@@ -341,14 +347,14 @@ const GET_AuditList = () => {
 onMounted(() => {
   if (route.query.type === 'view') {
     type.value = 'view';
-    id.value = route.query.id;
+    id.value = route.query.id as string;
     GET_goodsInventoryAddDetail();
-  }else{
+  } else if (route.query.type === 'edit') {
     type.value = 'edit';
-    id.value = route.query.id;
+    id.value = route.query.id as string;
     GET_goodsInventoryAddDetail();
   }
- /*  if (route.name === 'goodsInventoryAdd') {
+  /*  if (route.name === 'goodsInventoryAdd') {
     goodsInventoryAddForm.value.creator_id = user.value.uid;
     goodsInventoryAddForm.value.inventory_person_id = user.value.uid;
     goodsInventoryAddForm.value.dept_id = user.value.dept_id;
@@ -372,6 +378,9 @@ onMounted(() => {
     GET_AdministratorList();
     GET_WarehouseList();
   } */
+  goodsInventoryAddForm.value.creator_id = user.value.uid;
+  goodsInventoryAddForm.value.inventory_person_id = user.value.uid;
+  goodsInventoryAddForm.value.dept_id = user.value.dept_id;
   GET_AdministratorList();
   GET_WarehouseList();
   GET_DeptList();
@@ -467,14 +476,19 @@ const scanCode = () => {
     input.value.focus();
   });
 };
+/* 获取审核人名称 */
+const getNotice = (value: string) => {
+  const type = auditList.value.find((type: any) => type.id === value);
+  return type ? type.nickname : '未知类型';
+};
 
 const getadminList = (value: string) => {
   const type = adminList.value.find((type: any) => type.id === value);
-  return type ? type.real_name : '未知类型';
+  return type ? type.nickname : '未知类型';
 };
 
 const getRoleSplit = (value: string) => {
-  const type = typeList.value.find((type: any) => type.id === value);
+  const type = typeList.value.find((type: any) => type.value === value);
   return type ? type.label : '未知类型';
 };
 
@@ -506,7 +520,7 @@ const GET_AdministratorList = () => {
 };
 
 const handlePassGoodsInventory = () => {
-  store.dispatch('confirm', '确定通过吗?', '提示', { type: 'warning' }).then(() => {
+  /* store.dispatch('confirm', '确定通过吗?', '提示', { type: 'warning' }).then(() => {
     API_GoodsInventory.auditGoodsInventory(id.value, { status: 'PASS' })
       .then(() => {
         store.dispatch('message/success', '已通过!');
@@ -519,7 +533,7 @@ const handlePassGoodsInventory = () => {
         store.state.router.push({ name: 'goodsInventory' });
       })
       .catch(() => {});
-  });
+  }); */
 };
 
 const handleRejectGoodsInventory = () => {
@@ -527,8 +541,7 @@ const handleRejectGoodsInventory = () => {
     store.dispatch('message/error', '请填写驳回原因!');
     return;
   }
-  store
-    .dispatch('confirm', '确定拒绝吗?', '提示', { type: 'warning' })
+  ElMessageBox.confirm('确定拒绝吗?', '提示', { type: 'warning' })
     .then(() => {
       API_GoodsInventory.auditGoodsInventory(id.value, { status: 'REJECT', reject_reason: goodsInventoryAddForm.value.reject_reason }).then(() => {
         store.dispatch('message/success', '已拒绝!');

+ 317 - 0
src/views/stock/goodsInventoryLoss.vue

@@ -0,0 +1,317 @@
+<template>
+  <div>
+    <div class="search bg-white p-3">
+      <el-form :model="advancedForm" label-width="160px">
+        <el-row>
+          <el-col :span="6">
+            <el-form-item label="报损日期">
+              <el-date-picker
+                v-model="advancedForm.goodsInventory_time_range"
+                type="daterange"
+                align="center"
+                :editable="false"
+                unlink-panels
+                :clearable="true"
+                :default-time="['00:00:00', '23:59:59']"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                :picker-options="pickerOptions"
+              >
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="仓库">
+              <el-select v-model="advancedForm.warehouse_id">
+                <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="报损人">
+              <el-input v-model="advancedForm.creator" placeholder="请输入内容" width="200px"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="flex justify-end">
+        <el-button @click="advancedSearchEvent"> 搜索 </el-button>
+      </div>
+    </div>
+    <en-table-layout :tableData="tableData.data" :loading="loading" @selection-change="handleSelectionChange">
+      <template #toolbar>
+        <div class="inner-toolbar">
+          <div class="toolbar-btns">
+            <el-button size="mini" v-if="checkPermission(['goodsInventoryLoss:add'])" type="primary" @click="handleAddGoodsInventoryLoss">新增</el-button>
+          </div>
+        </div>
+      </template>
+
+      <template #table-columns>
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="sn" label="报损单编号">
+          <template #default="scope">
+            <span>{{ scope.row.sn }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="仓库">
+          <template #default="scope">{{ warehouseName(scope.row.warehouse_id) }}</template>
+        </el-table-column>
+        <el-table-column prop="status" label="状态">
+          <template #default="scope">{{ statusFilter(scope.row.status) }}</template>
+        </el-table-column>
+        <el-table-column prop="report_desc" label="报损说明" />
+        <el-table-column label="操作" width="450">
+          <template #default="scope">
+            <!-- v-if="checkPermission(['goodsInventoryLossDetail'])" -->
+            <el-button type="mini" size="mini" @click="handleDetailGoodsInventoryLoss(scope.row)">查看</el-button>
+            <!--  && checkPermission(['goodsInventoryLossEdit']) -->
+            <el-button type="mini" size="mini" v-if="scope.row.status == 'NOT_HANDLE'" @click="handleSubmitGoodsInventoryLoss(scope.row)">审核</el-button>
+          </template>
+        </el-table-column>
+      </template>
+
+      <el-pagination
+        v-if="tableData"
+        @size-change="handlePageSizeChange"
+        @current-change="handlePageCurrentChange"
+        :current-page="tableData.page_no"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="tableData.page_size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="tableData.data_total"
+      >
+      </el-pagination>
+    </en-table-layout>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { ref, onMounted, watch } from 'vue';
+import { useRouter, useRoute } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import * as API_GoodsInventoryLoss from '@/api/goodsInventoryLoss';
+import * as API_Setting from '@/api/setting';
+import * as API_BasicSetting from '@/api/basicSetting';
+/* import { Foundation } from '~/ui-utils'; */
+
+const router = useRouter();
+const route = useRoute();
+
+const warehouseList = ref<any>([]);
+const deptList = ref([]);
+const loading = ref(false);
+const params = ref<any>({
+  page_no: 1,
+  page_size: 10,
+});
+const advancedForm = ref<any>({
+  goodsInventory_time_range: [],
+});
+const tableData = ref<any>([]);
+const multipleSelection = ref([]);
+const inventoryType = ref([]);
+
+const GET_GoodsInventoryLossList = () => {
+  loading.value = true;
+  API_GoodsInventoryLoss.getGoodsInventoryLossList(params.value)
+    .then((response) => {
+      loading.value = false;
+      tableData.value = response;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+/* 时间选择限制器 */
+const pickerOptions = {
+  disabledDate(time: Date) {
+    return time.getTime() - 1 >= new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()).getTime() + 86400000 - 1;
+  },
+  shortcuts: [
+    {
+      text: '今天',
+      onClick(picker: any) {
+        const end = new Date();
+        const start = new Date(new Date().toDateString());
+        picker.$emit('pick', [start, end]);
+      },
+    },
+    {
+      text: '最近一周',
+      onClick(picker: any) {
+        const end = new Date();
+        const start = new Date();
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+        picker.$emit('pick', [start, end]);
+      },
+    },
+    {
+      text: '最近一个月',
+      onClick(picker: any) {
+        const end = new Date();
+        const start = new Date();
+        start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+        picker.$emit('pick', [start, end]);
+      },
+    },
+  ],
+};
+
+const GET_DeptList = () => {
+  /*  API_Setting.getDeptList().then((response) => {
+    deptList.value = Foundation.buildTree(response, '0');
+  }); */
+};
+
+const GET_WarehouseList = () => {
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    warehouseList.value = response;
+  });
+  API_Setting.getPage({ dictType: 'inventory_status' }).then((res) => {
+    inventoryType.value = res.data;
+  });
+};
+
+const handleDetailGoodsInventoryLoss = (row) => {
+  router.push({
+    name: 'goodsInventoryLossAdd',
+    query: { id: row.id, type: 'view' },
+  });
+};
+
+const warehouseName = (val) => {
+  let name = '';
+  warehouseList.value.map((el: any) => {
+    if (el.id == val) {
+      name = el.name;
+    }
+  });
+  return name;
+};
+
+const handleSubmitGoodsInventoryLoss = (row) => {
+  router.push({
+    name: 'goodsInventoryLossAdd',
+    query: { id: row.id,type:'examine' },
+  });
+};
+
+const handleAddGoodsInventoryLoss = () => {
+  router.push({
+    name: 'goodsInventoryLossAdd',
+  });
+};
+
+const statusFilter = (val) => {
+  let name = '';
+  inventoryType.value.map((el: any) => {
+    if (el.value == val) {
+      name = el.label;
+    }
+  });
+  return name;
+};
+
+const handleSelectionChange = (val) => {
+  multipleSelection.value = val;
+};
+
+const handlePageSizeChange = (size) => {
+  params.value.page_size = size;
+  GET_GoodsInventoryLossList();
+};
+
+const handlePageCurrentChange = (page) => {
+  params.value.page_no = page;
+  GET_GoodsInventoryLossList();
+};
+
+const advancedSearchEvent = () => {
+  params.value = {
+    ...params.value,
+    ...advancedForm.value,
+  };
+  delete params.value.start_time;
+  delete params.value.end_time;
+  if (advancedForm.value.goodsInventory_time_range) {
+    params.value.start_time = parseInt(Number(advancedForm.value.goodsInventory_time_range[0]) / 1000);
+    params.value.end_time = parseInt(Number(advancedForm.value.goodsInventory_time_range[1]) / 1000);
+  }
+  delete params.value.goodsInventory_time_range;
+  params.value.page_no = 1;
+  GET_GoodsInventoryLossList();
+};
+
+onMounted(() => {
+  GET_GoodsInventoryLossList();
+  GET_DeptList();
+  GET_WarehouseList();
+});
+
+/* watch(route, ({ query }) => {
+  params.value.page_no = 1;
+  GET_GoodsInventoryLossList();
+}); */
+</script>
+  
+  <!-- <style scoped lang="scss">
+  .search {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    overflow: hidden;
+    padding: 30px 10px 10px 10px;
+  
+    .el-form-item {
+      .el-form-item__content {
+        .el-input {
+          width: 200px;
+        }
+      }
+    }
+  
+    .el-button {
+      margin-top: -19px;
+      margin-left: 20px;
+    }
+  }
+  
+  .print {
+    margin-left: 790px;
+  }
+  
+  .deliverySheet-header {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  
+  .tips-t {
+    display: flex;
+    padding: 30px 0;
+  
+    div {
+      flex: 1;
+      text-align: left;
+      padding-left: 70px;
+    }
+  }
+  
+  .tips-f {
+    padding: 20px 0;
+  }
+  
+  .face-image {
+    display: block;
+    width: 50px;
+    height: 50px;
+    margin: 0 auto;
+  }
+  
+  .el-dialog__body {
+    padding: 10px 20px;
+  }
+  </style> -->

+ 735 - 0
src/views/stock/goodsInventoryLossAdd.vue

@@ -0,0 +1,735 @@
+<template>
+  <div class="bg-in-stock">
+    <el-form ref="goodsInventoryAddFormRef" :model="goodsInventoryAddForm" :rules="goodsInventoryAddFormRule" label-width="120px" inline class="change-form">
+      <h3 style="width: 100%">库存报损</h3>
+      <el-form-item label="报损时间" prop="report_time" class="change-form-item">
+        <span v-if="type == 'view'|| type == 'examine'">{{ goodsInventoryAddForm.report_time }}</span>
+        <el-date-picker
+          v-else
+          v-model="goodsInventoryAddForm.report_time"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="datetime"
+          :disabled="type === 'view' || type === 'examine' || type === 'edit'"
+          placeholder="选择日期时间"
+        >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="仓库" prop="warehouse_id" class="change-form-item">
+        <span v-if="type == 'view'|| type === 'examine'">{{ getWarehouse(goodsInventoryAddForm.warehouse_id) }}</span>
+        <el-select
+          v-else
+          v-model="goodsInventoryAddForm.warehouse_id"
+          @change="cleanGoodsList"
+          :disabled="type === 'view' || type === 'audit' || type === 'examine'"
+        >
+          <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="报损类型" prop="damage_type_value" class="change-form-item">
+        <span v-if="type == 'view'|| type === 'examine'">{{ getRoleSplit(goodsInventoryAddForm.damage_type_value) }}</span>
+        <el-select v-else v-model="goodsInventoryAddForm.damage_type_value" :disabled="type === 'view' || type === 'audit' || type === 'examine'">
+          <el-option v-for="item in roleSplit" :key="item.label" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="制单人" prop="creator_id" class="change-form-item">
+        <span v-if="type == 'view'|| type === 'examine'">{{ getadminList(goodsInventoryAddForm.creator_id) }}</span>
+        <el-select
+          v-else
+          v-model="goodsInventoryAddForm.creator_id"
+          :disabled="type === 'view' || type === 'audit' || type === 'examine'"
+          @change="changeCreator"
+        >
+          <el-option v-for="item in adminList" :key="item.id" :label="item.nickname" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否通知审核人:" prop="has_notice" class="change-form-item">
+        <el-switch v-model="goodsInventoryAddForm.has_notice" :disabled="type === 'examine'" inline-prompt :active-text="true" :inactive-text="false" /> </el-form-item
+      ><!-- v-if="goodsInventoryAddForm.has_notice" -->
+      <el-form-item label="审核人:" prop="notice_user_id" class="change-form-item" v-if="goodsInventoryAddForm.has_notice">
+        <span v-if="id && type !== 'examine'||type !== 'view'">{{ getNotice(goodsInventoryAddForm.notice_user_id) }}</span>
+        <el-select v-else v-model="goodsInventoryAddForm.notice_user_id" :disabled="type === 'view' || type === 'audit' || type === 'examine'">
+          <el-option v-for="item in auditList" :key="item.id" :label="item.nickname" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="报损说明" prop="report_desc" class="change-form-item" style="width: 61%">
+        <span v-if="type == 'view'|| type === 'examine'">{{ goodsInventoryAddForm.report_desc }}</span>
+        <el-input
+          v-else
+          style="flex: 1"
+          v-model="goodsInventoryAddForm.report_desc"
+          type="textarea"
+          :disabled="type === 'view' || type === 'audit' || type === 'examine'"
+          :autosize="{ minRows: 3, maxRows: 4 }"
+          placeholder="请输入报损说明"
+        ></el-input>
+      </el-form-item>
+      <div class="mx">
+        <h3>报损商品明细</h3>
+        <el-button v-if="type !== 'examine' && type !== 'audit' && type !== 'view'" class="button" size="mini" type="primary" @click="scanCode"
+          >录入SKU</el-button
+        >
+        <el-button v-if="type !== 'view'  type !== 'examine'" class="button" size="mini" type="primary" @click="handleSelectWarehouseEntryBatch">选择</el-button>
+      </div>
+      <div style="width: 100%; display: block">
+        <el-form-item style="width: 100%">
+          <el-table
+            :data="goodsInventoryAddForm.product_list"
+            border
+            :cell-style="{ textAlign: 'center' }"
+            :header-cell-style="{ textAlign: 'center' }"
+            style="width: 100%; margin-top: 20px"
+          >
+            <!--  <el-table-column label="商品编号">
+              <template #default="scope">
+                <span v-if="id"> {{ scope.row.goods_vo.sn }}</span>
+                <span v-else>{{ scope.row.goods_vo.sn }}</span>
+              </template>
+            </el-table-column> -->
+            <el-table-column label="商品名称">
+              <template #default="scope">
+                <span v-if="id">{{ scope.row.product_vo.name }}</span>
+                <span v-else>{{ scope.row.product_vo.name }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="sku">
+              <template #default="scope">
+                <span>{{ scope.row.product_vo.sku }}</span>
+              </template>
+            </el-table-column>
+            <!-- <el-table-column label="序列号" v-if="sn_code_list">
+              <template #default="scope">
+                <div class="sn-code-container">
+                  <span v-for="item in scope.row.sn_code_list" :key="item.id">
+                    <p>{{ item.sn_code }}</p>
+                  </span>
+                </div>
+              </template>
+            </el-table-column> 
+            <el-table-column prop="product_vo.spec_name" label="规格型号"> </el-table-column>-->
+            <el-table-column label="单位">
+              <template #default="scope">
+                <span v-if="!id"> {{ scope.row.product_vo.unit }}</span>
+                <span v-else> {{ scope.row.product_vo.unit }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="库存数量">
+              <template #default="scope">
+                {{ scope.row.usable_stock }}
+              </template>
+            </el-table-column>
+            <el-table-column label="报损数量">
+              <template #default="scope">
+                <span v-if="type == 'edit'">{{ scope.row.num }}</span>
+                <el-input
+                  v-else
+                  v-model="scope.row.report_num"
+                  type="number"
+                  :min="0"
+                  :maxlength="20"
+                  :disabled="type === 'view' || type === 'examine'"
+                ></el-input>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" v-if="type !== 'view' && type !== 'audit' && type !== 'examine'">
+              <template #default="scope">
+                <el-button size="mini" type="danger" @click="goodsInventoryAddForm.product_list.splice(scope.$index, 1)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </div>
+    </el-form>
+    <div class="footer">
+      <el-button v-if="type !== 'examine' && type !== 'audit' && type !== 'view'" type="primary" @click="submitGoodsInventoryAddForm">保存 </el-button>
+      <el-button v-if="type === 'edit'||type === 'examine'" type="primary" @click="submitcont">审核 </el-button>
+      <el-button v-if="type === 'edit'||type === 'examine'" type="primary" @click="submitreject">驳回 </el-button>
+      <el-button @click="printIng" v-if="type == 'view'">打印</el-button>
+      <el-button @click="$router.back()">返回 </el-button>
+    </div>
+    <el-dialog title="扫码录入" v-model="scanDialogVisible" width="30%" :close-on-click-modal="false">
+      <el-form ref="scanGoodsForm" :model="scanGoodsForm" inline label-width="60px">
+        <el-row>
+          <el-col :span="18">
+            <el-form-item label="sku:" prop="bar_code">
+              <el-input v-model="scanGoodsForm.bar_code" ref="input" @keyup.enter="toSearch()" :minlength="0" :maxlength="100"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="18">
+            <el-form-item label="序列号:" prop="sn_code">
+              <el-input v-model="sn_code" ref="sn_input" @keyup.enter="toSnCode()" :minlength="0" :maxlength="100"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <!--  <span slot="footer" class="dialog-footer">
+        </span> -->
+    </el-dialog>
+    <el-dialog title="提示" v-model="dialogVisible" width="30%">
+      <el-form ref="goodsInventoryAddForm" :model="goodsInventoryAddForm" label-width="120px" inline style="width: 900px">
+        <el-form-item label="驳回原因" prop="reject_reason">
+          <el-input v-model="goodsInventoryAddForm.reject_reason" type="textarea" :minlength="0" :maxlength="100"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleRejectGoodsInventoryLoss()">确 定</el-button>
+      </template>
+    </el-dialog>
+    <el-dialog title="报损商品" v-model="goodsVisible" width="1000px" @close="closeGoosData">
+      <div style="display: flex; align-items: center; justify-content: flex-end; padding: 10px 0">
+        <span>搜索商品:</span><el-input v-model="params.keyWord" style="width: 200px; margin-right: 5px"></el-input>
+        <el-button @click="searchGoodEvent"> 搜索 </el-button>
+      </div>
+      <el-table :data="goodsData.records" border style="width: 100%" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="product_vo.name" label="商品名称"></el-table-column>
+        <el-table-column prop="product_vo.sku" label="sku"> </el-table-column>
+        <el-table-column prop="" label="品牌">
+          <template #default="scope">
+            {{ scope.row.product_vo.brand }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="product_vo.weight" label="重量"> </el-table-column>
+        <el-table-column prop="product_vo.unit" label="单位"> </el-table-column>
+      </el-table>
+      <el-pagination
+        @size-change="goodsPageSizeChange"
+        @current-change="goodsPageCurrentChange"
+        :current-page="goodsData.current"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="goodsData.size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="goodsData.total"
+      >
+      </el-pagination>
+      <template #footer>
+        <el-button @click="closeGoosData">取 消</el-button>
+        <el-button type="primary" @click="submitGoosData()">确 定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { ref, onMounted, nextTick, reactive } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { useStore } from 'vuex';
+import * as API_GoodsInventoryLoss from '@/api/goodsInventoryLoss';
+import * as API_GoodsInventory from '@/api/goodsInventory';
+import * as API_GoodsExchange from '@/api/goodsExchange';
+import * as API_Setting from '@/api/setting';
+import * as API_BasicSetting from '@/api/basicSetting';
+import * as API_Auth from '@/api/auth';
+/*   import { Foundation, RegExp } from '~/ui-utils'; */
+
+const store = useStore();
+const route = useRoute();
+const router = useRouter();
+
+const adminList = ref<any>([]);
+const dialogVisible = ref(false);
+const warehouseList = ref<any>([]);
+const deptList = ref([]);
+const deptListAll = ref<any>([]);
+const roleSplit = ref<any>([]);
+const id = ref('');
+const type = ref('');
+const goodsInventoryAddForm = ref<any>({
+  product_list: [],
+  creator_id: '',
+  has_notice: false,
+});
+const goodsInventoryAddFormRule = ref({
+  warehouse_id: { required: true, message: '请选择报仓库', trigger: 'change' },
+  damage_type_value: { required: true, message: '请选择报损类型', trigger: 'change' },
+  dept_id: { required: true, message: '请选择所属部门', trigger: 'change' },
+  creator_id: { required: true, message: '请选择制单人', trigger: 'change' },
+});
+const warehouseProduct = ref(null);
+const scanDialogVisible = ref(false);
+const sn_code = ref('');
+const sku = ref('');
+const sn_code_list = ref([]);
+const index = ref('');
+const scanGoodsForm = ref<any>({});
+
+/* 获取审核人列表 */
+const auditList = ref<any>([]);
+const GET_AuditList = () => {
+  API_GoodsInventory.getUserByCompany().then((res) => {
+    auditList.value = res;
+  });
+};
+/* 获取审核人名称 */
+const getNotice = (value: string) => {
+  const type = auditList.value.find((type: any) => type.id === value);
+  return type ? type.nickname : '未知类型';
+};
+/* 报损商品信息 操作部分 */
+const goodsVisible = ref(false);
+const goodsData = ref<any>([]);
+const params = reactive({
+  page_no: 1,
+  page_size: 10,
+  keyWord: '',
+});
+/* 关闭报损商品 */
+const closeGoosData = () => {
+  goodsVisible.value = false;
+};
+/* 搜索报损商品 */
+const searchGoodEvent = () => {
+  API_GoodsExchange.getGoodsInfo(params, goodsInventoryAddForm.value.warehouse_id).then((res) => {
+    goodsData.value = res;
+  });
+};
+/* 选中的商品列表 */
+const goodsList = ref([]);
+const handleSelectionChange = (val) => {
+  goodsList.value = val.map((el) => {
+    /* el.product_id = el.id;
+    el.goods_id = el.id;
+    el.sn_code_list = []; */
+    return el;
+  });
+};
+const submitGoosData = () => {
+  if (goodsList.value.length >= 1) {
+    goodsInventoryAddForm.value.product_list = goodsList.value.map((el) => {
+      /* el.sn_code_list = []; */
+      return el;
+    });
+    goodsVisible.value = false;
+  } else {
+    ElMessage.error('请选择商品信息');
+  }
+};
+/* 盘点商品分页 */
+const goodsPageSizeChange = (size) => {
+  params.page_size = size;
+  searchGoodEvent();
+};
+
+const goodsPageCurrentChange = (page) => {
+  params.page_no = page;
+  searchGoodEvent();
+};
+
+const getadminList = (value: string) => {
+  const type = adminList.value.find((type) => type.id === value);
+  return type ? type.nickname : '未知类型';
+};
+
+const getRoleSplit = (value: string) => {
+  const type = roleSplit.value.find((type) => type.value === value);
+  return type ? type.label : '未知类型';
+};
+
+const getWarehouse = (value: string) => {
+  const type = warehouseList.value.find((type) => type.id === value);
+  return type ? type.name : '未知类型';
+};
+
+const cleanGoodsList = () => {
+  goodsInventoryAddForm.value.product_list = [];
+};
+
+const changeCreator = () => {
+  // Force update if necessary
+};
+
+const scanCode = () => {
+  scanDialogVisible.value = true;
+  nextTick(() => {
+    input.value.focus();
+  });
+};
+
+const sn_input = ref();
+const toSearch = () => {
+  API_GoodsExchange.getProduct(goodsInventoryAddForm.value.warehouse_id, scanGoodsForm.value.bar_code.replace(/\s+/g, '')).then((res) => {
+    res.sn_code_list = [];
+    sku.value = res.product_vo.sku;
+    const indexs = goodsInventoryAddForm.value.product_list.findIndex((el) => {
+      return el.goods_vo.id === res.goods_id && el.product_id === res.product_id && el.product_vo.sku === res.product_vo.sku;
+    });
+    if (indexs === -1) {
+      index.value = goodsInventoryAddForm.value.product_list.length;
+      goodsInventoryAddForm.value.product_list.push(res);
+    } else {
+      index.value = indexs;
+    }
+    if (res.product_vo.have_sn) {
+      nextTick(() => {
+        sn_input.value.focus();
+      });
+    } else {
+      goodsInventoryAddForm.value.product_list[index.value].report_num += 1;
+      if (goodsInventoryAddForm.value.product_list[index.value].report_num == goodsInventoryAddForm.value.product_list[index.value].num) {
+        scanDialogVisible.value = false;
+      }
+    }
+  });
+};
+const input = ref();
+const toSnCode = () => {
+  if (sku.value == '') return ElMessage.error('请录入正确的sku');
+  API_GoodsExchange.getSnCode('out', sku.value, sn_code.value.replace(/\s+/g, '')).then((res) => {
+    sn_code.value = '';
+    let exists = goodsInventoryAddForm.value.product_list[index.value].sn_code_list.find((item) => item.sn_code === res.sn_code && item.sku === res.sku);
+    if (!exists) {
+      goodsInventoryAddForm.value.product_list[index.value].sn_code_list.push(res);
+    }
+    goodsInventoryAddForm.value.product_list[index.value].report_num = goodsInventoryAddForm.value.product_list[index.value].sn_code_list.length;
+    const indexs = goodsInventoryAddForm.value.product_list.findIndex((el) => {
+      return el.goods_id === res.goods_id && el.product_id === res.product_id && el.product_vo.sku === res.sku;
+    });
+    goodsInventoryAddForm.value.product_list[index.value].id = goodsInventoryAddForm.value.product_list[indexs].id;
+    scanGoodsForm.value.bar_code = '';
+    nextTick(() => {
+      input.value.focus();
+    });
+  });
+};
+
+const goodsInventoryAddFormRef = ref();
+const submitGoodsInventoryAddForm = () => {
+  goodsInventoryAddFormRef.value.validate((valid: boolean) => {
+    if (valid) {
+      const params = { ...goodsInventoryAddForm.value };
+      if (params.dept_id) {
+        params.dept_name = deptListAll.value.find((dept) => dept.id === params.dept_id).name;
+      }
+      if (params.warehouse_id) {
+        params.warehouse_name = warehouseList.value.find((ware) => ware.id === params.warehouse_id).name;
+      }
+      if (params.damage_type_value) {
+        params.damage_type_key = roleSplit.value.find((ware) => ware.value === params.damage_type_value).label;
+      }
+      if (params.creator_id) {
+        params.creator = adminList.value.find((admin) => admin.id === params.creator_id).real_name;
+      }
+      params.product_list = params.product_list.map((item) => {
+        const query = {
+          report_num: item.report_num,
+          product_id: item.product_id,
+          product_stock_id: item.id,
+          sn_code_list: item.sn_code_list,
+        };
+        return query;
+      });
+      if (id.value) {
+        API_GoodsInventoryLoss.editgoodsInventoryLossAdd(id.value, params).then(() => {
+          ElMessage.success('修改成功!');
+          /* const { callback } = route.params;
+            if (typeof callback === 'function') callback();
+            store.dispatch('delCurrentViews', {
+              view: route,
+              $router: router
+            }); */
+          router.push({ name: 'goodsInventoryLoss' });
+        });
+      } else {
+        API_GoodsInventoryLoss.addgoodsInventoryLossAdd(params).then(() => {
+          ElMessage.success('添加成功!');
+          /* const { callback } = route.params;
+            if (typeof callback === 'function') callback();
+            store.dispatch('delCurrentViews', {
+              view: route,
+              $router: router
+            }); */
+          router.push({ name: 'goodsInventoryLoss' });
+        });
+      }
+    }
+  });
+};
+
+const submitcont = () => {
+  goodsInventoryAddFormRef.value.validate((valid: boolean) => {
+    if (valid) {
+      const params = { ...goodsInventoryAddForm.value };
+      if (params.dept_id) {
+        params.dept_name = deptListAll.value.find((dept) => dept.id === params.dept_id).name;
+      }
+      if (params.warehouse_id) {
+        params.warehouse_name = warehouseList.value.find((ware) => ware.id === params.warehouse_id).name;
+      }
+      if (params.damage_type_value) {
+        params.damage_type_key = roleSplit.value.find((ware) => ware.value === params.damage_type_value).label;
+      }
+      if (params.creator_id) {
+        params.creator = adminList.value.find((admin) => admin.id === params.creator_id).real_name;
+      }
+      params.product_list = params.product_list.map((item) => {
+        const query = {
+          report_num: item.report_num,
+          product_id: item.product_id,
+          product_stock_id: item.product_stock_id,
+        };
+        return query;
+      });
+      API_GoodsInventoryLoss.submit(id.value, params).then(() => {
+        ElMessage.success('审核成功!');
+        /*  const { callback } = route.params;
+          if (typeof callback === 'function') callback();
+          store.dispatch('delCurrentViews', {
+            view: route,
+            $router: router
+          }); */
+        router.push({ name: 'goodsInventoryLoss' });
+      });
+    }
+  });
+};
+
+const submitreject = () => {
+  goodsInventoryAddFormRef.value.validate((valid: boolean) => {
+    if (valid) {
+      const params = { ...goodsInventoryAddForm.value };
+      if (params.dept_id) {
+        params.dept_name = deptListAll.value.find((dept) => dept.id === params.dept_id).name;
+      }
+      if (params.warehouse_id) {
+        params.warehouse_name = warehouseList.value.find((ware) => ware.id === params.warehouse_id).name;
+      }
+      if (params.damage_type_value) {
+        params.damage_type_key = roleSplit.value.find((ware) => ware.value === params.damage_type_value).label;
+      }
+      if (params.creator_id) {
+        params.creator = adminList.value.find((admin) => admin.id === params.creator_id).real_name;
+      }
+      params.status = 'CANCEL_HANDLE';
+      params.product_list = params.product_list.map((item) => {
+        const query = {
+          report_num: item.report_num,
+          product_id: item.product_id,
+          product_stock_id: item.product_stock_id,
+        };
+        return query;
+      });
+      API_GoodsInventoryLoss.submit(id.value, params).then(() => {
+        ElMessage.success('驳回成功!');
+        const { callback } = route.params;
+        /* if (typeof callback === 'function') callback();
+        store.dispatch('delCurrentViews', {
+          view: route,
+          $router: router
+        }); */
+        router.push({ name: 'goodsInventoryLoss' });
+      });
+    }
+  });
+};
+
+const handlePassGoodsInventoryLoss = () => {
+  ElMessageBox.confirm('确定通过吗?', '提示', { type: 'warning' })
+    .then(() => {
+      API_GoodsInventoryLoss.auditGoodsInventoryLoss(id.value, { status: 'PASS' }).then(() => {
+        ElMessage.success('已通过!');
+        /* const { callback } = route.params;
+      if (typeof callback === 'function') callback();
+      store.dispatch('delCurrentViews', {
+        view: route,
+        $router: router
+      }); */
+        router.push({ name: 'goodsInventoryLoss' });
+      });
+    })
+    .catch(() => {});
+};
+
+const handleRejectGoodsInventoryLoss = () => {
+  ElMessageBox.confirm('确定拒绝吗?', '提示', { type: 'warning' })
+    .then(() => {
+      API_GoodsInventoryLoss.auditGoodsInventoryLoss(id.value, { status: 'REJECT', reject_reason: goodsInventoryAddForm.value.reject_reason }).then(() => {
+        ElMessage.success('已拒绝!');
+        /* const { callback } = route.params;
+      if (typeof callback === 'function') callback();
+      store.dispatch('delCurrentViews', {
+        view: route,
+        $router: router
+      }); */
+        router.push({ name: 'goodsInventoryLoss' });
+      });
+    })
+    .catch(() => {});
+};
+
+const handleSelectWarehouseEntryBatch = async () => {
+  if (!goodsInventoryAddForm.value.warehouse_id) {
+    ElMessage.error('请先选择仓库!');
+    return;
+  }
+  API_GoodsExchange.getGoodsInfo(params, goodsInventoryAddForm.value.warehouse_id, 'gt').then((res) => {
+    goodsData.value = res;
+    goodsVisible.value = true;
+  });
+  /*  const goodsData = await EnwarehouseEntryBatch({
+    goodsApi: `/admin/erp/warehouseOut/getGoodByWarehouse/${goodsInventoryAddForm.value.warehouse_id}`,
+    warehouseList: warehouseList.value,
+    selectedIds: id.value ? goodsInventoryAddForm.value.product_list.map((item) => item.id) : goodsInventoryAddForm.value.product_list.map((item) => item.id),
+    purchasePlanApiParams: { warehouse_id: goodsInventoryAddForm.value.warehouse_id },
+  });
+  goodsInventoryAddForm.value.warehouse_id = goodsData.warehouse_id;
+  goodsInventoryAddForm.value.product_list = goodsData.purchasePlans; */
+};
+
+const GET_AdministratorList = () => {
+  API_Auth.getAdministratorList({
+    page_no: 1,
+    page_size: 9999,
+    user_state: 0,
+  }).then((response) => {
+    adminList.value = response.data;
+  });
+};
+
+const GET_DictDataInfo = () => {
+  API_Setting.getDictDataInfo('es_stock_damage_report').then((response) => {
+    roleSplit.value = response;
+  });
+};
+
+const GET_WarehouseList = (e: any) => {
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    warehouseList.value = response;
+  });
+};
+
+const GET_DeptList = () => {
+  /* API_Setting.getDeptList().then(response => {
+    deptList.value = Foundation.buildTree(response, '0');
+    deptListAll.value = response;
+  }); */
+};
+
+const GET_goodsInventoryAddDetail = () => {
+  API_GoodsInventoryLoss.getGoodsInventoryLossInfo(id.value).then((response) => {
+    response.product_list.map((el) => {
+      el.num = el.report_num;
+    });
+    goodsInventoryAddForm.value = response;
+    goodsInventoryAddForm.value.distribution_name = response.staff_name;
+  });
+};
+
+onMounted(() => {
+    if(route.query.type==='view'){
+        type.value = 'view';
+        id.value=route.query.id as string
+        GET_goodsInventoryAddDetail()
+    }else if(route.query.type==='examine'){
+        type.value = 'examine';
+        id.value=route.query.id as string
+        GET_goodsInventoryAddDetail()
+    }
+  /*if (route.name === 'goodsInventoryLossEdit') {
+    type.value = 'edit';
+  } else if (route.name === 'goodsInventoryLossAudit') {
+    type.value = 'audit';
+  } else if (route.name === 'goodsInventoryLossReturn') {
+    type.value = 'return';
+  } else if (route.name === 'goodsInventoryLossAdd') {
+    type.value = 'add';
+   
+    GET_WarehouseList({ dept_id: store.state.user.dept_id });
+  } else if (route.name === 'goodsInventoryLossDetail') {
+    type.value = 'detail';
+  }
+  if (route.params.id) {
+    id.value = route.params.id;
+    GET_goodsInventoryAddDetail();
+  }
+   GET_DeptList(); */
+  goodsInventoryAddForm.value.creator_id = store.state.user.uid;
+  goodsInventoryAddForm.value.dept_id = store.state.user.dept_id;
+  GET_DictDataInfo();
+  GET_WarehouseList({ dept_id: store.state.user.dept_id });
+  GET_AdministratorList();
+  GET_AuditList();
+});
+</script>
+
+<style scoped>
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+
+.mx {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+
+.mx .button {
+  margin-left: 10px;
+}
+
+.change-form {
+  display: flex;
+  justify-content: flex-start;
+  align-items: flex-start;
+  flex-wrap: wrap;
+  min-width: 900px;
+}
+
+.change-form .change-form-item {
+  width: 30%;
+  margin: 0 10px 20px 0;
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+}
+
+.change-form .el-form-item__content {
+  flex: 1;
+  width: 100%;
+}
+
+.change-form .el-date-editor,
+.change-form .el-cascader,
+.change-form .el-select {
+  width: 100%;
+}
+
+.bg-in-stock {
+  background-color: #fff;
+  margin: 10px;
+  padding: 25px;
+}
+
+.goods-info {
+  display: flex;
+}
+
+.goods-info .goods-name-box {
+  text-align: left;
+}
+
+.goods-info .goods-name-box .goods-name {
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  line-height: 16px;
+}
+
+.goods-info .goods-name-box .specs {
+  color: #999999;
+}
+
+.el-input--suffix .el-input__inner {
+  padding-right: 10px;
+}
+
+.error-input .el-input__inner {
+  border: 1px solid red;
+}
+</style>

+ 372 - 0
src/views/stock/goodsUnderstock.vue

@@ -0,0 +1,372 @@
+<template>
+  <div>
+    <div class="search bg-white p-3">
+      <el-form :model="advancedForm" label-width="160px">
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="调出仓库">
+              <el-select v-model="advancedForm.out_warehouse_id">
+                <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="调入仓库">
+              <el-select v-model="advancedForm.in_warehouse_id">
+                <el-option v-for="item in warehouseList" :key="item.id" :label="item.name" :value="item.id" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="状态">
+              <el-select v-model="advancedForm.status">
+                <el-option v-for="item in statusList" :key="item.id" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="时间">
+              <el-date-picker
+                v-model="advancedForm.purchasePlan_time_range"
+                type="daterange"
+                align="center"
+                :editable="false"
+                unlink-panels
+                :clearable="true"
+                :default-time="['00:00:00', '23:59:59']"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                value-format="timestamp"
+                :picker-options="{
+                  disabledDate(time) {
+                    return time.getTime() - 1 >= new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()).getTime() + 86400000 - 1;
+                  },
+                  /*  shortcuts: MixinPickerShortcuts, */
+                }"
+              >
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="调拨单号">
+              <el-input v-model="advancedForm.sn" placeholder="请输入调拨单号"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="flex justify-end">
+        <el-button @click="advancedSearchEvent"> 搜索 </el-button>
+      </div>
+    </div>
+    <en-table-layout :tableData="tableData.data" :loading="loading" @selection-change="handleSelectionChange">
+      <template #toolbar>
+        <div class="inner-toolbar">
+          <div class="toolbar-btns">
+            <el-button size="mini" v-if="checkPermission(['goodsUnderstock:add'])" type="primary" @click="handleAddGoodsUnderstock">新增</el-button>
+          </div>
+        </div>
+      </template>
+
+      <template #table-columns>
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="sn" label="调拨单编号">
+          <template #default="scope">
+            <span>{{ scope.row.sn }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="调拨时间">
+          <template #default="scope">{{ scope.row.transfer_time }}</template>
+        </el-table-column>
+        <el-table-column prop="out_warehouse_name" label="调出仓库">
+          <template #default="scope">
+            {{ warehouseName(scope.row.out_warehouse_id) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="in_warehouse_name" label="调入仓库">
+          <template #default="scope">
+            {{ warehouseName(scope.row.in_warehouse_id) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="" label="配送方式">
+          <template #default="scope">
+            {{ getTypename(scope.row.send_type) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="状态">
+          <template #default="scope">{{ get_typeName(scope.row.status) }}</template>
+        </el-table-column>
+        <el-table-column label="操作" width="250">
+          <template #default="scope">
+            <el-button size="mini" @click="handleSubmitGoodsTransfer(scope.row)">查看</el-button
+            ><!-- v-if="checkPermission(['goodsUnderstockDetail'])" -->
+          </template>
+        </el-table-column>
+      </template>
+      <template #pagination>
+        <el-pagination
+          v-if="tableData"
+          @size-change="handlePageSizeChange"
+          @current-change="handlePageCurrentChange"
+          :current-page="tableData.page_no"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="tableData.page_size"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="tableData.data_total"
+        >
+        </el-pagination>
+      </template>
+    </en-table-layout>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { ref, onMounted, computed, watch } from 'vue';
+import { useStore } from 'vuex';
+import * as API_GoodsTransfer from '@/api/goodsTransfer';
+import * as API_Statistics from '@/api/statistics';
+import * as API_Setting from '@/api/setting';
+import * as API_BasicSetting from '@/api/basicSetting';
+import * as API_Express from '@/api/express';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { useRouter, useRoute } from 'vue-router';
+
+const store = useStore();
+const router = useRouter();
+const route = useRoute();
+const user = computed(() => store.getters.user);
+
+const warehouseList = ref<any[]>([]);
+const goodstransferType = ref<any[]>([]);
+const loading = ref(false);
+const params = ref({
+  page_no: 1,
+  page_size: 10,
+});
+const advancedForm = ref<any>({});
+const tableData = ref<any>({});
+const multipleSelection = ref<any[]>([]);
+const deliveryTypeList = ref<any[]>([]);
+const statusList = ref<any[]>([]);
+
+const GET_GoodsTransferList = () => {
+  loading.value = true;
+  API_Statistics.getstockTransferStatistics(params.value)
+    .then((response) => {
+      loading.value = false;
+      tableData.value = response;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+
+const GET_DictDataInfo = () => {
+  API_Setting.getDictDataInfo('erp_goodstransfer_type').then((res) => {
+    goodstransferType.value = res;
+  });
+  API_Setting.getPage({ dictType: 'transfer_status' }).then((res) => {
+    statusList.value = res.data;
+  });
+};
+
+const GET_WarehouseList = () => {
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    warehouseList.value = response;
+  });
+};
+
+const GET_ExpressList = () => {
+  API_Express.getExpressList(params.value).then((response) => {
+    deliveryTypeList.value = response.data;
+  });
+};
+
+const get_typeName = (val: string) => {
+  let name = '';
+  statusList.value.map((el) => {
+    if (el.value == val) {
+      name = el.label;
+    }
+  });
+  return name;
+};
+
+const getTypename = (val: string) => {
+  let name = '';
+  deliveryTypeList.value.map((el) => {
+    if (el.id == val) {
+      name = el.name;
+    }
+  });
+  return name;
+};
+
+const warehouseName = (val: string) => {
+  let name = '';
+  warehouseList.value.map((el) => {
+    if (el.id == val) {
+      name = el.name;
+    }
+  });
+  return name;
+};
+
+const handleSuccessGoodsTransfer = (row: any) => {
+  API_GoodsTransfer.get_withdraw(row.id).then(() => {
+    ElMessage.success('撤销成功!');
+    GET_GoodsTransferList();
+  });
+};
+
+const handleRejectGoodsTransfer = (row: any) => {
+  API_GoodsTransfer.rejectGoodsTransfer(row.id, { in_handled_by_id: user.value.uid, in_handled_by_name: user.value.username }).then(() => {
+    ElMessage.success('退回成功!');
+    GET_GoodsTransferList();
+  });
+};
+
+const handleSubmitGoodsTransfer = (row: any) => {
+  router.push({
+    name: 'goodsUnderstockAdd',
+    query: { id: row.id, type: 'view' },
+  });
+  /*  store.dispatch('router/push', {
+    name: 'goodsUnderstockDetail',
+    params: { id: row.id },
+  }); */
+};
+
+const handleWithdrawGoodsTransfer = (row: any) => {
+  API_GoodsTransfer.withdrawGoodsTransfer(row.id).then(() => {
+    ElMessage.success('撤回成功!');
+    GET_GoodsTransferList();
+  });
+};
+
+const handleDeleteGoodsTransfer = () => {
+  if (!multipleSelection.value.length) return store.dispatch('message/error', '请先选择!');
+  ElMessageBox.confirm('确定要删除这些商品调拨吗?', '提示', { type: 'warning' })
+    .then(() => {
+      const ids = multipleSelection.value.map((item) => item.id);
+      API_GoodsTransfer.deleteGoodsTransfer(ids).then(() => {
+        store.dispatch('message/success', '删除成功!');
+        GET_GoodsTransferList();
+      });
+    })
+    .catch(() => {});
+};
+
+const handleSelectionChange = (val: any[]) => {
+  multipleSelection.value = val;
+};
+
+const handlePageSizeChange = (size: number) => {
+  params.value.page_size = size;
+  GET_GoodsTransferList();
+};
+
+const handlePageCurrentChange = (page: number) => {
+  params.value.page_no = page;
+  GET_GoodsTransferList();
+};
+
+const handleAddGoodsUnderstock = () => {
+  router.push({
+    name: 'goodsUnderstockAdd',
+  });
+};
+
+const handleEditGoodsTransfer = (row: any) => {
+  /* store.dispatch('router/push', {
+    name: 'goodsTransferEdit',
+    params: { id: row.id },
+  }); */
+};
+
+const searchEvent = (data: any) => {
+  params.value = {
+    ...params.value,
+    sn: data,
+  };
+  Object.keys(advancedForm.value).forEach((key) => delete params.value[key]);
+  params.value.page_no = 1;
+  GET_GoodsTransferList();
+};
+
+const advancedSearchEvent = () => {
+  params.value = {
+    ...params.value,
+    ...advancedForm.value,
+  };
+  delete params.value.start_time;
+  delete params.value.end_time;
+  if (advancedForm.value.purchasePlan_time_range) {
+    params.value.start_time = parseInt(Number(advancedForm.value.purchasePlan_time_range[0]) / 1000);
+    params.value.end_time = parseInt(Number(advancedForm.value.purchasePlan_time_range[1]) / 1000);
+  }
+  delete params.value.purchasePlan_time_range;
+  params.value.page_no = 1;
+  GET_GoodsTransferList();
+};
+
+onMounted(() => {
+  GET_GoodsTransferList();
+  GET_DictDataInfo();
+  GET_WarehouseList();
+  GET_ExpressList();
+});
+
+/* watch(
+  () => store.state.route.query,
+  () => {
+    params.value.page_no = 1;
+    GET_GoodsTransferList();
+  }
+); */
+</script>
+  
+ <!--  <style lang="scss" scoped>
+  .search {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    overflow: hidden;
+    padding: 30px 10px 10px 10px;
+    /deep/ .el-form-item {
+      .el-form-item__content {
+        .el-input {
+          width: 200px;
+        }
+      }
+    }
+    .el-button {
+      margin-top: -19px;
+      margin-left: 20px;
+    }
+  }
+  .tips-t {
+    display: flex;
+    padding: 10px 0;
+  
+    div {
+      flex: 1;
+      text-align: center;
+    }
+  }
+  
+  .tips-f {
+    padding: 20px 0;
+  }
+  
+  .face-image {
+    display: block;
+    width: 50px;
+    height: 50px;
+    margin: 0 auto;
+  }
+  
+  /deep/ .el-dialog__body {
+    padding: 10px 20px;
+  }
+  </style> -->

+ 475 - 0
src/views/stock/goodsUnderstockAdd.vue

@@ -0,0 +1,475 @@
+<template>
+  <div class="bg-in-stock">
+    <el-form ref="GoodsTransferFormRef" :model="GoodsTransferForm" label-width="120px" :rules="GoodsTransferFormRule" inline>
+      <h3>调拨单</h3>
+      <el-form-item label="调拨时间" prop="transfer_time" class="change-form-item">
+        <span v-if="type === 'view'">{{ GoodsTransferForm.transfer_time }}</span>
+        <el-date-picker
+          v-else
+          v-model="GoodsTransferForm.transfer_time"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="datetime"
+          :disabled="type === 'view' || type === 'audit' || type === 'check'"
+          placeholder="选择日期时间"
+        >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item prop="out_warehouse_id" label="调出仓库">
+        <span v-if="type === 'view'">{{ getWarehouse(GoodsTransferForm.out_warehouse_id) }}</span>
+        <el-select v-else @change="cleanGoodsList" v-model="GoodsTransferForm.out_warehouse_id" :disabled="type === 'view'">
+          <el-option v-for="item in WarehouseList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="in_warehouse_id" label="调入仓库">
+        <span v-if="type === 'view'">{{ getWarehouse(GoodsTransferForm.in_warehouse_id) }}</span>
+        <el-select v-else v-model="GoodsTransferForm.in_warehouse_id" :disabled="type === 'view'">
+          <el-option v-for="item in WarehouseList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="配送方式" prop="send_type">
+        <span v-if="type === 'view'">{{ getdeliveryType(GoodsTransferForm.send_type) }}</span>
+        <el-select v-else v-model="GoodsTransferForm.send_type" clearable :disabled="type === 'view'">
+          <el-option v-for="item in deliveryTypeList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <span v-if="type === 'view'">{{ GoodsTransferForm.remark }}</span>
+        <el-input v-else :disabled="type === 'view'" type="textarea" :rows="2" placeholder="请输入内容" v-model="GoodsTransferForm.remark"> </el-input>
+      </el-form-item>
+      <div class="mx">
+        <h3>商品明细</h3>
+        <el-button class="button" size="mini" type="primary" v-if="type !== 'view'" @click="handleSelectWarehouseEntryBatch">选择</el-button>
+      </div>
+      <div style="display: block">
+        <el-table
+          :data="GoodsTransferForm.product_list"
+          border
+          :cell-style="{ textAlign: 'center' }"
+          :header-cell-style="{ textAlign: 'center' }"
+          style="width: 100%; margin-top: 20px"
+        >
+         <!--  <el-table-column label="商品编号">
+            <template #default="scope">
+              <span>{{ scope.row.goods_vo.sn }}</span>
+            </template>
+          </el-table-column> -->
+          <el-table-column label="商品名称">
+            <template #default="scope">
+              <span>{{ scope.row.product_vo.name }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="sku">
+            <template #default="scope">
+              <span>{{ scope.row.product_vo.sku }}</span>
+            </template>
+          </el-table-column>
+       <!--    <el-table-column label="序列号">
+            <template #default="scope">
+              <span>{{ scope.row.product_vo.sn_code }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="product_vo.spec_name" label="规格型号"></el-table-column> -->
+          <el-table-column label="单位">
+            <template #default="scope">
+              <span>{{ scope.row.product_vo.unit }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="库存数量">
+            <template #default="scope">
+              <span>{{ scope.row.usable_stock }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="调拨数量">
+            <template #default="scope">
+              <span v-if="type === 'view'">{{ scope.row.num }}</span>
+              <el-input
+                v-else
+                v-model="scope.row.num"
+                type="number"
+                :min="0"
+                :maxlength="20"
+                :disabled="type === 'view' || type === 'audit' || type === 'check'"
+              ></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" v-if="type !== 'view'">
+            <template #default="scope">
+              <el-button size="mini" type="danger" @click="GoodsTransferForm.product_list.splice(scope.$index, 1)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </el-form>
+    <div class="footer">
+      <el-button v-if="type !== 'view'" type="primary" @click="submitGoodsTransferForm">保存</el-button>
+      <el-button @click="printIng">打印</el-button>
+      <el-button @click="roBack">返回</el-button>
+    </div>
+    <el-dialog title="调拨商品" v-model="goodsVisible" width="1000px" @close="closeGoosData">
+      <div style="display: flex; align-items: center; justify-content: flex-end; padding: 10px 0">
+        <span>搜索商品:</span><el-input v-model="params.keyWord" style="width: 200px; margin-right: 5px"></el-input>
+        <el-button @click="searchGoodEvent"> 搜索 </el-button>
+      </div>
+      <el-table :data="goodsData.records" border style="width: 100%" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="product_vo.name" label="商品名称"></el-table-column>
+        <el-table-column prop="product_vo.sku" label="sku"> </el-table-column>
+        <el-table-column prop="" label="品牌">
+          <template #default="scope">
+            {{ scope.row.product_vo.brand }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="product_vo.weight" label="重量"> </el-table-column>
+        <el-table-column prop="product_vo.unit" label="单位"> </el-table-column>
+      </el-table>
+      <el-pagination
+        @size-change="goodsPageSizeChange"
+        @current-change="goodsPageCurrentChange"
+        :current-page="goodsData.current"
+        :page-sizes="[10, 20, 50, 100]"
+        :page-size="goodsData.size"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="goodsData.total"
+      >
+      </el-pagination>
+      <template #footer>
+        <el-button @click="closeGoosData">取 消</el-button>
+        <el-button type="primary" @click="submitGoosData()">确 定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+  
+  <script lang="ts" setup>
+import { ref, onMounted, computed,reactive } from 'vue';
+import { useStore } from 'vuex';
+import * as API_GoodsTransfer from '@/api/goodsTransfer';
+import * as API_BasicSetting from '@/api/basicSetting';
+import * as API_Setting from '@/api/setting';
+import * as API_Auth from '@/api/auth';
+import * as API_Express from '@/api/express';
+import * as API_GoodsExchange from '@/api/goodsExchange';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { useRouter, useRoute } from 'vue-router';
+
+const router = useRouter();
+const route = useRoute();
+
+const store = useStore();
+const user = computed(() => store.getters.user);
+
+const adminList = ref<any[]>([]);
+const WarehouseList = ref<any[]>([]);
+const inWarehouseList = ref<any[]>([]);
+const deptList = ref<any[]>([]);
+const deptListAll = ref<any[]>([]);
+const goodstransferType = ref<any[]>([]);
+const fileList = ref<any[]>([]);
+const id = ref<string>('');
+const type = ref<string>('');
+const deliveryTypeList = ref<any[]>([]);
+const GoodsTransferForm = ref<any>({
+  out_dept_id: '',
+  out_handled_by_id: '',
+  product_list: [],
+});
+const GoodsTransferFormRule = ref({
+  transfer_time: {
+    required: true,
+    message: '请选择调整时间',
+    trigger: 'change',
+  },
+  out_warehouse_id: {
+    required: true,
+    message: '请选择调出仓库',
+    trigger: 'change',
+  },
+  in_warehouse_id: {
+    required: true,
+    message: '请选择调入仓库',
+    trigger: 'change',
+  },
+  send_type: {
+    required: true,
+    message: '请选择配送方式',
+    trigger: 'change',
+  },
+});
+
+const getdeliveryType = (value: string) => {
+  const type = deliveryTypeList.value.find((type) => type.id === value);
+  return type ? type.name : '未知类型';
+};
+
+const getWarehouse = (value: string) => {
+  const type = WarehouseList.value.find((type) => type.id === value);
+  return type ? type.name : '未知类型';
+};
+
+const printIng = () => {
+  // 打印功能
+};
+/* 报损商品信息 操作部分 */
+const goodsVisible = ref(false);
+const goodsData = ref<any>([]);
+const params = reactive({
+  page_no: 1,
+  page_size: 10,
+  keyWord: '',
+});
+/* 关闭报损商品 */
+const closeGoosData = () => {
+  goodsVisible.value = false;
+};
+/* 搜索报损商品 */
+const searchGoodEvent = () => {
+  API_GoodsExchange.getGoodsInfo(params, GoodsTransferForm.value.out_warehouse_id).then((res) => {
+    goodsData.value = res;
+  });
+};
+/* 选中的商品列表 */
+const goodsList = ref([]);
+const handleSelectionChange = (val) => {
+  goodsList.value = val.map((el) => {
+    /* el.product_id = el.id;
+    el.goods_id = el.id;
+    el.sn_code_list = []; */
+    return el;
+  });
+};
+const submitGoosData = () => {
+  if (goodsList.value.length >= 1) {
+    GoodsTransferForm.value.product_list = goodsList.value.map((el) => {
+      /* el.sn_code_list = []; */
+      return el;
+    });
+    goodsVisible.value = false;
+  } else {
+    ElMessage.error('请选择商品信息');
+  }
+};
+/* 盘点商品分页 */
+const goodsPageSizeChange = (size) => {
+  params.page_size = size;
+  searchGoodEvent();
+};
+
+const goodsPageCurrentChange = (page) => {
+  params.page_no = page;
+  searchGoodEvent();
+};
+
+const changeDept = () => {
+  GET_WarehouseList({ dept_id: GoodsTransferForm.value.out_dept_id });
+  cleanGoodsList();
+};
+
+const cleanGoodsList = () => {
+  GoodsTransferForm.value.product_list = [];
+};
+
+const GET_AdministratorList = () => {
+  API_Auth.getAdministratorList({
+    page_no: 1,
+    page_size: 9999,
+    user_state: 0,
+  }).then((response) => {
+    adminList.value = response.data;
+  });
+};
+
+const roBack = () => {
+  /* const { callback } = store.state.route.params;
+  if (typeof callback === 'function') callback();
+  store.dispatch('delCurrentViews', {
+    view: store.state.route,
+    $router: store.state.router,
+  }); */
+ router.push({ name: 'goodsUnderstock' });
+};
+
+const handleSelectWarehouseEntryBatch = async () => {
+  if (!GoodsTransferForm.value.out_warehouse_id) {
+    ElMessage.error('请先选择调出仓库!');
+    return;
+  }
+  API_GoodsExchange.getGoodsInfo(params, GoodsTransferForm.value.out_warehouse_id, 'gt').then((res) => {
+    goodsData.value = res;
+    goodsVisible.value = true;
+  });
+  /* const goodsData = await store.dispatch('EnwarehouseEntryBatch', {
+    goodsApi: `/admin/erp/warehouseOut/getGoodByWarehouse/${GoodsTransferForm.value.out_warehouse_id}`,
+    warehouseList: WarehouseList.value,
+    selectedIds: id.value ? GoodsTransferForm.value.product_list.map((item: any) => item.id) : GoodsTransferForm.value.product_list.map((item: any) => item.id),
+    purchasePlanApiParams: {
+      warehouse_id: GoodsTransferForm.value.out_warehouse_id,
+    },
+  });
+  GoodsTransferForm.value.out_warehouse_id = goodsData.warehouse_id;
+  if (goodsData.purchasePlans && goodsData.purchasePlans.length) {
+    GoodsTransferForm.value.product_list = goodsData.purchasePlans.map((item: any) => {
+      item.warehouse_entry_batch_id = item.id;
+      return item;
+    });
+  } */
+};
+const GoodsTransferFormRef = ref();
+const submitGoodsTransferForm = () => {
+  GoodsTransferFormRef.value.validate((valid: boolean) => {
+    if (valid) {
+      const params = { ...GoodsTransferForm.value };
+      if (params.product_list.length === 0) {
+        ElMessage.error('请选择商品!');
+        return;
+      }
+      if (params.in_warehouse_id === params.out_warehouse_id) {
+        ElMessage.error('调出和调入仓库不能一致!');
+        return;
+      }
+      params.product_list = params.product_list.map((item: any) => ({
+        num: item.num,
+        goods_id: item.goods_id,
+        usable_stock: Number(item.usable_stock),
+        product_id: item.product_id,
+        product_stock_id: item.id,
+      }));
+      if (id.value) {
+        API_GoodsTransfer.editGoodsTransfer(id.value, params).then(() => {
+            ElMessage.success('修改成功!');
+         /*  const { callback } = store.state.route.params;
+          if (typeof callback === 'function') callback();
+          store.dispatch('delCurrentViews', {
+            view: store.state.route,
+            $router: store.state.router,
+          }); */
+          router.push({ name: 'goodsUnderstock' });
+        });
+      } else {
+        API_GoodsTransfer.addGoodsTransfer(params).then(() => {
+            ElMessage.success('添加成功!');
+          /* const { callback } = store.state.route.params;
+          if (typeof callback === 'function') callback();
+          store.dispatch('delCurrentViews', {
+            view: store.state.route,
+            $router: store.state.router,
+          }); */
+          router.push({ name: 'goodsUnderstock' });
+        });
+      }
+    }
+  });
+};
+
+const GET_DeptList = () => {
+  API_Setting.getDeptList().then((response) => {
+    deptList.value = response;
+    deptListAll.value = response;
+  });
+};
+
+const GET_WarehouseList = (value:any) => {
+  API_BasicSetting.getWarehouseListAll().then((response) => {
+    WarehouseList.value = response;
+  });
+};
+
+const GET_DictDataInfo = () => {
+  API_Setting.getDictDataInfo('erp_goodstransfer_type').then((res) => {
+    goodstransferType.value = res;
+  });
+};
+
+const GET_GoodsTransferDetail = () => {
+  API_GoodsTransfer.getGoodsTransferInfo(id.value).then((response) => {
+    GoodsTransferForm.value = response;
+  });
+};
+
+const GET_ExpressList = () => {
+  API_Express.getExpressList({}).then((response) => {
+    deliveryTypeList.value = response.data;
+  });
+};
+
+onMounted(() => {
+ /*  if (store.state.route.name === 'goodsTransferAdd') {
+    GoodsTransferForm.value.out_handled_by_id = user.value.uid;
+    GoodsTransferForm.value.dept_id = user.value.dept_id;
+  } else if (store.state.route.name === 'goodsUnderstockDetail') {
+    id.value = store.state.route.params.id;
+    type.value = 'detail';
+  }
+  if (store.state.route.params.id) {
+    id.value = store.state.route.params.id;
+    GET_GoodsTransferDetail();
+  } */
+ if(route.query.type==='view'){
+    type.value=route.query.type
+    id.value = route.query.id as string;
+    GET_GoodsTransferDetail();
+ }
+  GET_DeptList();
+  GET_DictDataInfo();
+  GET_AdministratorList();
+  GET_WarehouseList({ dept_id: user.value.dept_id });
+  GET_ExpressList();
+});
+</script>
+  
+<style scoped>
+.footer {
+  width: 100%;
+  padding: 10px;
+  bottom: 0px;
+  text-align: center;
+  z-index: 999;
+}
+
+.mx {
+  display: flex;
+  align-items: center;
+}
+
+.mx .button {
+  margin-left: 10px;
+}
+
+.bg-in-stock {
+  background-color: #fff;
+  margin: 10px;
+  padding: 25px;
+}
+
+.goods-info {
+  display: flex;
+}
+
+.goods-info .goods-name-box {
+  text-align: left;
+}
+
+.goods-info .goods-name-box .goods-name {
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  line-height: 16px;
+}
+
+.goods-info .goods-name-box .specs {
+  color: #999999;
+}
+
+::v-deep .el-input--suffix .el-input__inner {
+  padding-right: 10px;
+}
+
+::v-deep .error-input .el-input__inner {
+  border: 1px solid red;
+}
+
+::v-deep .el-form-item {
+  width: 350px;
+}
+</style>

+ 4 - 4
src/views/templateManage/accountTemplate.vue

@@ -83,7 +83,7 @@
         </el-col>
         <el-col :span="12">
           <el-form-item label="模版名称:" prop="name">
-            <el-input v-model="accountForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版名称"></el-input>
+            <el-input v-model="accountForm.name"  :disabled="disabled" clearable placeholder="请输入模版名称"></el-input>
           </el-form-item>
         </el-col>
         <!-- <el-form-item label="短信类型:" prop="template_type">
@@ -95,7 +95,7 @@
           </el-form-item> -->
         <el-col :span="12">
           <el-form-item label="模版code:" prop="code">
-            <el-input v-model="accountForm.code" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版code"></el-input>
+            <el-input v-model="accountForm.code"  :disabled="disabled" clearable placeholder="请输入模版code"></el-input>
           </el-form-item>
         </el-col>
         <el-col :span="12">
@@ -116,7 +116,7 @@
                 @onCreated="handleCreated"
               />
             </div> -->
-          <el-input v-model="accountForm.content"  type="textarea" :autosize="{ minRows: 3, maxRows: 4 }" :disabled="disabled" clearable placeholder="请输入模版内容"></el-input>
+          <el-input v-model="accountForm.content"  type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" :disabled="disabled" clearable placeholder="请输入模版内容"></el-input>
         </el-form-item>
     </el-col>
         <el-col :span="24">
@@ -170,7 +170,7 @@ const accountFormRules = ref<any>({
   content: [{ required: true, message: '请输入模版内容', trigger: 'blur' }],
   code: [
     { required: true, message: '请输入模版code', trigger: 'blur' },
-    { pattern: /^[a-zA-Z0-9]+$/, message: '只能输入英文和数字,不能包含空格', trigger: 'blur' },
+    { pattern: /^[a-zA-Z0-9_]+$/, message: '只能输入英文、数字和下划线,不能包含空格', trigger: 'blur' },
   ],
   template_type: [{ required: true, message: '请选择短信类型', trigger: 'change' }],
   /*  user_num: [{ required: true, message: '请输入可创建用户数', trigger: 'blur' }], */

+ 4 - 4
src/views/templateManage/emailtemplate.vue

@@ -83,7 +83,7 @@
         </el-col>
         <el-col :span="12">
           <el-form-item label="模版名称:" prop="name">
-            <el-input v-model="EmailForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版名称"></el-input>
+            <el-input v-model="EmailForm.name" :disabled="disabled" clearable placeholder="请输入模版名称"></el-input>
           </el-form-item>
         </el-col>
         <!-- <el-form-item label="短信类型:" prop="template_type">
@@ -95,7 +95,7 @@
         </el-form-item> -->
         <el-col :span="12">
           <el-form-item label="模版code:" prop="code">
-            <el-input v-model="EmailForm.code" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版code"></el-input>
+            <el-input v-model="EmailForm.code" :disabled="disabled" clearable placeholder="请输入模版code"></el-input>
           </el-form-item>
         </el-col>
         <el-col :span="12">
@@ -115,7 +115,7 @@
               @onCreated="handleCreated"
             />
           </div>
-          <!-- <el-input v-model="EmailForm.content" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版内容"></el-input> -->
+          <!-- <el-input v-model="EmailForm.content" :disabled="disabled" clearable placeholder="请输入模版内容"></el-input> -->
         </el-form-item>
         <el-col :span="24">
           <el-form-item label="模版说明:" prop="remark">
@@ -195,7 +195,7 @@ const EmailFormRules = ref<any>({
   content: [{ required: true, message: '请输入模版内容', trigger: 'blur' }],
   code: [
     { required: true, message: '请输入模版code', trigger: 'blur' },
-    { pattern: /^[a-zA-Z0-9]+$/, message: '只能输入英文和数字,不能包含空格', trigger: 'blur' },
+    { pattern: /^[a-zA-Z0-9_]+$/, message: '只能输入英文、数字和下划线,不能包含空格', trigger: 'blur' },
   ],
   template_type: [{ required: true, message: '请选择短信类型', trigger: 'change' }],
   /*  user_num: [{ required: true, message: '请输入可创建用户数', trigger: 'blur' }], */

+ 13 - 8
src/views/templateManage/smsTemplate.vue

@@ -40,7 +40,7 @@
 
     <template #table-columns>
       <el-table-column prop="name" label="模版名称" />
-      <el-table-column prop="template_type" label="短信类型" />
+      <!-- <el-table-column prop="template_type" label="短信类型" /> -->
       <el-table-column prop="remark" label="模版说明" />
       <el-table-column prop="audit_status" label="审核状态" />
       <el-table-column prop="enable_status" label="状态">
@@ -88,21 +88,24 @@
       <el-form-item label="模版名称:" prop="name">
         <el-input v-model="SMSForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版名称"></el-input>
       </el-form-item>
-      <el-form-item label="短信类型:" prop="template_type">
+      <el-form-item label="平台模版code:" prop="template_code">
+        <el-input v-model="SMSForm.template_code" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入平台模版code"></el-input>
+      </el-form-item>
+     <!--  <el-form-item label="短信类型:" prop="template_type">
         <el-select v-model="SMSForm.template_type" clearable :disabled="disabled" placeholder="请选择短信类型">
           <el-option label="验证码" value="0" />
           <el-option label="短信通知" value="1" />
           <el-option label="推广短信" value="2" />
         </el-select>
-      </el-form-item>
-      <el-form-item label="模版code:" prop="code">
+      </el-form-item> -->
+      <el-form-item label="自定义模版code:" prop="code">
         <el-input v-model="SMSForm.code" :disabled="disabled" clearable placeholder="请输入模版code"></el-input>
       </el-form-item>
       <el-form-item label="是否启用:" prop="enable_status">
         <el-switch v-model="SMSForm.enable_status" inline-prompt :disabled="disabled" active-text="启用" inactive-text="禁用" />
       </el-form-item>
        <el-form-item label="模版内容:" prop="content">
-        <el-input v-model="SMSForm.content"  :disabled="disabled" :autosize="{ minRows: 3}" clearable placeholder="请输入模版内容"></el-input>
+        <el-input v-model="SMSForm.content"  :disabled="disabled" type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" clearable placeholder="请输入模版内容"></el-input>
       </el-form-item>
       <el-form-item label="模版说明:" prop="remark">
         <el-input v-model="SMSForm.remark" type="textarea" :disabled="disabled" :autosize="{ minRows: 3, maxRows: 4 }" placeholder="请输入模版说明"></el-input>
@@ -138,17 +141,19 @@ const SMSForm = ref<any>({
   enable_status: false,
   remark: '',
   type: 'SMS',
+  template_code:''
 });
 const SMSFormRules = ref<any>({
   pid: [{ required: true, message: '请选择上级模板', trigger: 'change' }],
   name: [{ required: true, message: '请输入模版名称', trigger: 'blur' }],
+  template_code: [{ required: true, message: '请输入平台模版code', trigger: 'blur' }],
   content: [{ required: true, message: '请输入模版内容', trigger: 'blur' }],
   code: [
     { required: true, message: '请输入模版code', trigger: 'blur' },
-    { pattern: /^[a-zA-Z0-9]+$/, message: '只能输入英文和数字,不能包含空格', trigger: 'blur' },
+    { pattern: /^[a-zA-Z0-9_]+$/, message: '只能输入英文、数字和下划线,不能包含空格', trigger: 'blur' },
   ],
-  template_type: [{ required: true, message: '请选择短信类型', trigger: 'change' }],
-  /*  user_num: [{ required: true, message: '请输入可创建用户数', trigger: 'blur' }], */
+  /*template_type: [{ required: true, message: '请选择短信类型', trigger: 'change' }],
+    user_num: [{ required: true, message: '请输入可创建用户数', trigger: 'blur' }], */
 });
 /* 新增 */
 const handleAddRole = () => {

+ 4 - 4
src/views/templateManage/systemMessage.vue

@@ -81,13 +81,13 @@
   >
     <el-form :model="systemForm" :rules="systemFormRules" ref="systemFormRef" label-width="120px">
       <el-form-item label="模版名称:" prop="name">
-        <el-input v-model="systemForm.name" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版名称"></el-input>
+        <el-input v-model="systemForm.name"  :disabled="disabled" clearable placeholder="请输入模版名称"></el-input>
       </el-form-item>
       <el-form-item label="模版内容:" prop="content">
-        <el-input v-model="systemForm.content" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版内容"></el-input>
+        <el-input v-model="systemForm.content"  type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" :disabled="disabled" clearable placeholder="请输入模版内容"></el-input>
       </el-form-item>
       <el-form-item label="模版code:" prop="code">
-        <el-input v-model="systemForm.code" :minlength="2" :maxlength="20" :disabled="disabled" clearable placeholder="请输入模版code"></el-input>
+        <el-input v-model="systemForm.code"  :disabled="disabled" clearable placeholder="请输入模版code"></el-input>
       </el-form-item>
       <el-form-item label="是否启用:" prop="enable_status">
         <el-switch v-model="systemForm.enable_status" inline-prompt :disabled="disabled" active-text="启用" inactive-text="禁用" />
@@ -137,7 +137,7 @@ const systemFormRules = ref<any>({
   content: [{ required: true, message: '请输入模版内容', trigger: 'blur' }],
   code: [
     { required: true, message: '请输入模版code', trigger: 'blur' },
-    { pattern: /^[a-zA-Z0-9]+$/, message: '只能输入英文和数字,不能包含空格', trigger: 'blur' },
+    { pattern: /^[a-zA-Z0-9_]+$/, message: '只能输入英文、数字和下划线,不能包含空格', trigger: 'blur' },
   ],
   /* enable_status: [{ required: true, message: '请选择状态', trigger: 'change' }],
     user_num: [{ required: true, message: '请输入可创建用户数', trigger: 'blur' }], */