lhl il y a 3 mois
Parent
commit
555bf345a0
48 fichiers modifiés avec 4376 ajouts et 816 suppressions
  1. 1 1
      index.html
  2. 5 2
      package.json
  3. 206 191
      pnpm-lock.yaml
  4. 5 0
      src/api/erp/index.ts
  5. 37 4
      src/api/goods/index.ts
  6. 21 0
      src/api/goods/types.ts
  7. 5 0
      src/api/marketing/index.ts
  8. 4 0
      src/api/store/index.ts
  9. 1 0
      src/api/system/department/types.ts
  10. 17 7
      src/components/StoreList/src/storeList.vue
  11. 46 0
      src/components/UpFile/src/components/upFile.vue
  12. 3 3
      src/components/UpFile/src/index.vue
  13. 3 0
      src/main.ts
  14. 8 0
      src/router/model/Goods.ts
  15. 8 0
      src/router/model/Store.ts
  16. 303 0
      src/utils/newToExcel.ts
  17. 2 2
      src/views/Authorization/Role/Role.vue
  18. 35 5
      src/views/Authorization/User/User.vue
  19. 51 1
      src/views/Authorization/User/components/Write.vue
  20. 368 110
      src/views/Erp/Adjust/Adjust.vue
  21. 42 24
      src/views/Erp/Adjust/AdjustEdit.vue
  22. 2 2
      src/views/Erp/Check/CheckEdit.vue
  23. 240 3
      src/views/Erp/Losses/Losses.vue
  24. 3 3
      src/views/Erp/Losses/LossesEdit.vue
  25. 426 110
      src/views/Erp/Out/Out.vue
  26. 46 41
      src/views/Erp/Out/OutEdit.vue
  27. 354 94
      src/views/Erp/Purchase/Purchase.vue
  28. 5 5
      src/views/Erp/Role/Role.vue
  29. 336 7
      src/views/Erp/Simple/Simple.vue
  30. 319 4
      src/views/Erp/Want/Want.vue
  31. 100 43
      src/views/Goods/edit/add.vue
  32. 39 17
      src/views/Goods/list/index.vue
  33. 127 0
      src/views/Goods/unit/components/Write.vue
  34. 268 0
      src/views/Goods/unit/index.vue
  35. 25 2
      src/views/Marketing/Rechange/Rechange.vue
  36. 58 6
      src/views/Marketing/coupon/components/Write.vue
  37. 2 1
      src/views/Marketing/coupon/index.vue
  38. 16 3
      src/views/Marketing/coupon/list.vue
  39. 293 98
      src/views/Order/orderList/index.vue
  40. 2 2
      src/views/Store/Role/Role.vue
  41. 174 0
      src/views/Store/area/components/Write.vue
  42. 245 0
      src/views/Store/area/index.vue
  43. 68 1
      src/views/Store/list/components/Write.vue
  44. 37 7
      src/views/Store/list/index.vue
  45. 10 9
      src/views/System/class/index.vue
  46. 8 6
      src/views/User/list/components/DetailFrom.vue
  47. 1 1
      src/views/User/list/components/Write.vue
  48. 1 1
      src/views/User/list/index.vue

+ 1 - 1
index.html

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="zh-CN">
   <head>
     <meta charset="UTF-8" />
     <link rel="icon" href="/favicon.ico" />

+ 5 - 2
package.json

@@ -43,6 +43,8 @@
     "echarts": "^5.6.0",
     "echarts-wordcloud": "^2.1.0",
     "element-plus": "^2.9.2",
+    "exceljs": "^4.4.0",
+    "file-saver": "^2.0.5",
     "lodash-es": "^4.17.21",
     "mitt": "^3.0.1",
     "monaco-editor": "^0.52.2",
@@ -51,6 +53,7 @@
     "pinia-plugin-persistedstate": "^3.2.3",
     "qrcode": "^1.5.4",
     "qs": "^6.13.1",
+    "tlbs-map-vue": "^1.2.1",
     "url": "^0.11.4",
     "vue": "^3.5.13",
     "vue-draggable-plus": "^0.5.6",
@@ -58,8 +61,8 @@
     "vue-json-pretty": "^2.4.0",
     "vue-router": "^4.5.0",
     "vue-types": "^5.1.3",
-    "xgplayer": "^3.0.20",
-    "tlbs-map-vue": "^1.2.1"
+    "vue3-print-nb": "^0.1.4",
+    "xgplayer": "^3.0.20"
   },
   "devDependencies": {
     "@commitlint/cli": "^19.6.1",

Fichier diff supprimé car celui-ci est trop grand
+ 206 - 191
pnpm-lock.yaml


+ 5 - 0
src/api/erp/index.ts

@@ -96,6 +96,11 @@ export const getOut = (params:object): Promise<IResponse> => {
   return request.get({ url: `${REQUEST_BASE}/outbound`, params })
 }
 
+export const delOut = (id:number): Promise<IResponse> => {
+  return request.delete({ url: `${REQUEST_BASE}/outbound/${id}` })
+}
+
+
 export const getOutGood = (params:object): Promise<IResponse> => {
   return request.get({ url: `${REQUEST_BASE}/outbound/goods`, params })
 }

+ 37 - 4
src/api/goods/index.ts

@@ -6,9 +6,11 @@ import {
   goodsSearch,
   auditData,
   searchProductRule,
+  searchProductUnit,
   productRule,
   productRuleValue,
-  goodsDatas
+  goodsDatas,
+  productUnit
 } from './types'
 import { productDataParse } from './parseData'
 export const getProductCategory = (params: {
@@ -19,10 +21,10 @@ export const getProductCategory = (params: {
   return request.get({ url: `${REQUEST_BASE}/product_category`, params })
 }
 export const addProductCategory = (data: categoryData): Promise<IResponse> => {
-  return request.post({ url: `${REQUEST_BASE}/product_category/save`, data })
+  return request.post({ url: `${REQUEST_BASE}/product_category`, data })
 }
 export const delProductCategory = (id: number): Promise<IResponse> => {
-  return request.post({ url: `${REQUEST_BASE}/product_category/delete/${id}` })
+  return request.delete({ url: `${REQUEST_BASE}/product_category/${id}` })
 }
 export const putProductCategory = (data: categoryData): Promise<IResponse> => {
   return request.put({ url: `${REQUEST_BASE}/product_category/${data.id}`, data })
@@ -35,7 +37,7 @@ export const addProduct = (data: goodsDatas): Promise<IResponse> => {
   return request.post({ url: `${REQUEST_BASE}/product`, data: pushData })
 }
 export const delProduct = (id: number, is_del: 0 | 1): Promise<IResponse> => {
-  return request.post({ url: `${REQUEST_BASE}/product/delete/${id}`, data: { is_del } })
+  return request.delete({ url: `${REQUEST_BASE}/product/${id}`, data: { is_del } })
 }
 export const putProduct = (data: goodsDatas): Promise<IResponse> => {
   const pushData = productDataParse(data)
@@ -148,3 +150,34 @@ export const getAttrSelectList = (id: number, attrs: productRuleValue[]): Promis
     data: { attrs }
   })
 }
+
+
+export const getUnitList =  (params: searchProductUnit): Promise<IResponse> => {
+  return request.get({
+    url: `${REQUEST_BASE}/configure`,
+    params
+  })
+}
+
+export const addProductUnit = (data: productUnit): Promise<IResponse> => {
+  return request.post({
+    url: `${REQUEST_BASE}/configure`,
+    data
+  })
+}
+export const putProductUnit = (data: any): Promise<IResponse> => {
+  return request.put({
+    url: `${REQUEST_BASE}/configure/${data.id}`,
+    data
+  })
+}
+export const delProductUnit = (id: number): Promise<IResponse> => {
+  return request.delete({
+    url: `${REQUEST_BASE}/configure/${id}`
+  })
+}
+export const getProductUnitDetail = (id: number): Promise<IResponse> => {
+  return request.get({
+    url: `${REQUEST_BASE}/configure/${id}`
+  })
+}

+ 21 - 0
src/api/goods/types.ts

@@ -88,6 +88,7 @@ export interface goodsDatas {
   specs: object[]
 }
 export interface goodsSearch {
+  store_name?: string
   name?: string
   page?: number
   limit?: number
@@ -108,6 +109,15 @@ export interface searchProductRule {
   page?: number
   limit?: number
 }
+export interface searchProductUnit {
+  name?: string
+  page?: number
+  limit?: number
+  type: string
+  is_show?: number
+  is_weigh?: number
+  pid?: number
+}
 export interface productRuleValue {
   attrHidden: '' | true | false
   detail: string[]
@@ -139,4 +149,15 @@ export interface brandDate {
   id?: number
   brand_name?: string
   status?: number
+}
+
+export interface productUnit {
+  name: string
+  id: number
+  type: string
+  pid?: number
+  sort?: number
+  is_show?: number
+  path: string
+  is_weigh: number
 }

+ 5 - 0
src/api/marketing/index.ts

@@ -17,6 +17,11 @@ export const editCoupon = (data: any): Promise<IResponse> => {
   return request.put({ url: `${REQUEST_BASE}/coupon/${data.id}`, data })
 }
 
+// change_field
+export const changeCouponField = (data: any): Promise<IResponse> => {
+  return request.post({ url: `${REQUEST_BASE}/coupon_issue/setstatus/${data.id}`, data })
+}
+
 export const delCoupon = (id: number): Promise<IResponse> => {
   return request.delete({ url: `${REQUEST_BASE}/coupon/${id}` })
 }

+ 4 - 0
src/api/store/index.ts

@@ -20,3 +20,7 @@ export const delStore = (id: number): Promise<IResponse> => {
 export const getStoreDetail = (id: number): Promise<IResponse> => {
   return request.get({ url: `${REQUEST_BASE}/store/${id}` })
 }
+
+export const storeExport = (): Promise<IResponse> => {
+  return request.get({ url: `${REQUEST_BASE}/store/export` })
+}

+ 1 - 0
src/api/system/department/types.ts

@@ -22,6 +22,7 @@ export interface AddAdmins {
   phone: string | number //手机号
   roles: string[] | number[] //角色数组
   status: string | number //是否启用
+  configure_id?: number //区域id
 }
 export interface putAdmins {
   id: string | number //账号

+ 17 - 7
src/components/StoreList/src/storeList.vue

@@ -35,8 +35,8 @@ const tableColumns = reactive<TableColumn[]>([
     minWidth: '60px'
   },
   {
-    field: 'info',
-    label: '头像',
+    field: 'logo',
+    label: 'LOGO',
     align: 'center',
     headerAlign: 'center',
     minWidth: '60px',
@@ -45,8 +45,8 @@ const tableColumns = reactive<TableColumn[]>([
         const row = data.row
         return (
           <>
-            <ElAvatar shape="circle" size="small" src={row.avatar}>
-              <img src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png" />
+            <ElAvatar shape="circle" size="small" src={row.logo}>
+              <img src={row.logo} />
             </ElAvatar>
           </>
         )
@@ -55,7 +55,7 @@ const tableColumns = reactive<TableColumn[]>([
   },
   {
     field: 'name',
-    label: '姓名',
+    label: '仓库名称',
     minWidth: '90px'
   },
   {
@@ -64,7 +64,7 @@ const tableColumns = reactive<TableColumn[]>([
     minWidth: '130px'
   },
   {
-    field: 'detail_address',
+    field: 'detailed_address',
     label: '地址',
     minWidth: '130px'
   },
@@ -98,7 +98,17 @@ const searchSchema = reactive<FormSchema[]>([
     label: '搜索',
     component: 'Input',
     componentProps: {
-      placeholder: '姓名查询'
+      placeholder: '仓库名称查询'
+    }
+  },
+  {
+    field: 'type',
+    label: '搜索',
+    component: 'Input',
+    value: 3,
+    hidden: true,
+    componentProps: {
+      placeholder: ''
     }
   }
 ])

+ 46 - 0
src/components/UpFile/src/components/upFile.vue

@@ -79,6 +79,42 @@ const uploadImage = ref<UploadInstance>()
 const uploadVideo = ref<UploadInstance>()
 const saveLoading = ref(false)
 const uploadFileNum = ref(0)
+// 判断是否为图片链接的函数
+const isImageUrl = (url: string): boolean => {
+  if (!url) return false
+  
+  // 检查是否为有效的URL格式
+  try {
+    new URL(url)
+  } catch {
+    return false
+  }
+  
+  // 常见的图片扩展名
+  const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', '.ico']
+  
+  // 检查URL路径是否以图片扩展名结尾(不区分大小写)
+  const lowerCaseUrl = url.toLowerCase()
+  return imageExtensions.some(ext => lowerCaseUrl.includes(ext))
+}
+// 判断是否为视频链接的函数
+const isVideoUrl = (url: string): boolean => {
+  if (!url) return false
+  
+  // 检查是否为有效的URL格式
+  try {
+    new URL(url)
+  } catch {
+    return false
+  }
+  
+  // 常见的视频扩展名
+  const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.webm', '.mpeg', '.mpg']
+  
+  // 检查URL路径是否以视频扩展名结尾(不区分大小写)
+  const lowerCaseUrl = url.toLowerCase()
+  return videoExtensions.some(ext => lowerCaseUrl.includes(ext))
+}
 const confirm = async () => {
   console.log(form.fileList, 'form.fileList')
   saveLoading.value = true
@@ -92,6 +128,16 @@ const confirm = async () => {
     return
   }
   if (form.type == '2') {
+    if (props.fileType === 1 && !isImageUrl(form.images)) {
+      ElMessage.error('请输入有效的图片链接地址')
+      saveLoading.value = false
+      return
+    }
+    if (props.fileType === 2 && !isVideoUrl(form.images)) {
+      ElMessage.error('请输入有效的视频链接地址')
+      saveLoading.value = false
+      return
+    }
     const re = await upOnlineFile({ pid: form.pid, images: form.images })
     if (re) {
       uploadFileNum.value = 0

+ 3 - 3
src/components/UpFile/src/index.vue

@@ -292,7 +292,7 @@ const delData = async (id?: string) => {
       <Search :schema="searchSchema" @reset="setSearchParams" @search="setSearchParams" />
       <div class="mb-10px">
         <BaseButton type="primary" :icon="icon" @click="AddAction">{{
-          fileType == 1 ? '上传图片' : '上传视'
+          fileType == 1 ? '上传图片' : '上传视'
         }}</BaseButton>
         <BaseButton
           :loading="delLoading"
@@ -309,9 +309,9 @@ const delData = async (id?: string) => {
             <ElTooltip effect="dark" :content="item.name" placement="top">
               <div class="flex align-center">
                 <div class="white-nowrap">{{ item.name }}</div>
-                <BaseButton link size="small" type="primary" @click="editorTitle(item)">
+                <!-- <BaseButton link size="small" type="primary" @click="editorTitle(item)">
                   修改
-                </BaseButton>
+                </BaseButton> -->
               </div>
             </ElTooltip>
           </template>

+ 3 - 0
src/main.ts

@@ -35,6 +35,8 @@ import TlbsMap from 'tlbs-map-vue'
 
 import { createApp } from 'vue'
 
+import print from 'vue3-print-nb'
+
 import App from './App.vue'
 
 import './permission'
@@ -42,6 +44,7 @@ import './permission'
 const setupAll = async () => {
   const app = createApp(App)
   app.use(TlbsMap)
+  app.use(print)
   await setupI18n(app)
 
   setupStore(app)

+ 8 - 0
src/router/model/Goods.ts

@@ -50,6 +50,14 @@ export default {
       meta: {
         title: '商品规格'
       }
+    },
+    {
+      path: 'unit',
+      component: () => import('@/views/Goods/unit/index.vue'),
+      name: `${pre}-unit`,
+      meta: {
+        title: '单位列表'
+      }
     }
   ]
 }

+ 8 - 0
src/router/model/Store.ts

@@ -36,5 +36,13 @@ export default {
         title: '门店角色'
       }
     },
+    {
+      path: 'area',
+      component: () => import('@/views/Store/area/index.vue'),
+      name: `${pre}-area`,
+      meta: {
+        title: '区域列表'
+      }
+    }
   ]
 }

+ 303 - 0
src/utils/newToExcel.ts

@@ -0,0 +1,303 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2024 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+// import { isEmpty } from 'element-ui/lib/utils/util';
+import ExcelJS from 'exceljs'
+import * as FileSaver from 'file-saver'
+
+const isEmpty = (val:any) => {
+  // null or undefined
+  if (val == null) return true;
+
+  if (typeof val === 'boolean') return false;
+
+  if (typeof val === 'number') return !val;
+
+  if (val instanceof Error) return val.message === '';
+
+  switch (Object.prototype.toString.call(val)) {
+    // String or Array
+    case '[object String]':
+    case '[object Array]':
+      return !val.length;
+
+    // Map or Set or File
+    case '[object File]':
+    case '[object Map]':
+    case '[object Set]':
+      {
+        return !val.size;
+      }
+    // Plain Object
+    case '[object Object]':
+      {
+        return !Object.keys(val).length;
+      }
+  }
+
+  return false;
+}
+
+interface SheetStyle {
+  properties?: {
+    tabColor?: { argb: string };
+    defaultRowHeight?: number;
+  };
+}
+
+type SheetConfig = [string, SheetStyle] | string;
+
+type ExcelData = (string | (string[])[] )[][];
+
+export default function createWorkBook(
+  header: string[], 
+  title: string | string[], 
+  data: ExcelData, 
+  foot: string | string[], 
+  filename?: string,
+  sheets?: SheetConfig
+): void {
+  const letter = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
+  let lcomun = 1;
+  let worksheet: ExcelJS.Worksheet;
+
+  const workBook: ExcelJS.Workbook = new ExcelJS.Workbook(); 
+  let long = header.length;
+
+  /**
+   *  创建工作薄
+   * @param sheets 
+   */
+  function createSheets(sheets: SheetConfig | undefined): void {
+    let sheet: string;
+    let style: SheetStyle = {};
+    
+    if (Array.isArray(sheets)) {
+      sheet = sheets[0];
+      style = sheets[1] || {};
+    } else {
+      sheet = sheets || 'Sheet1';
+    }
+    
+    worksheet = workBook.addWorksheet(sheet, style);
+  }
+
+  /**
+   *  设置表名介绍等
+   * @param title 
+   * @param long 
+   */
+  function setTitle(title: string | string[] | undefined, long: number): void {
+    if (isEmpty(title)) return;
+    
+    const titles: string[] = Array.isArray(title) ? title : (title as string).split(',');
+    
+    for (let i = 0; i < titles.length; i++) {
+      let ti = worksheet.getRow(i + 1);
+      ti.getCell(1).value = titles[i];
+      ti.height = 30;
+      ti.font = { bold: true, size: 20, vertAlign: 'subscript' };
+      ti.alignment = { vertical: 'bottom', horizontal: 'center' };
+      ti.outlineLevel = 1;
+      worksheet.mergeCells(i + 1, 1, i + 1, long);
+      ti.commit();
+      lcomun++;
+    }
+  }
+
+  /**
+   *  设置表头行
+   * @param header 
+   */
+  function setHeader(header: string[]): void {
+    if (isEmpty(header)) return;
+    
+    const headerRow = worksheet.getRow(lcomun) as any;
+    for (let index = 1; index <= header.length; index++) {
+      headerRow.getCell(index).value = header[index - 1];
+    }
+    
+    headerRow.height = 25;
+    headerRow.width = 50;
+    headerRow.font = { bold: true, size: 18, vertAlign: 'subscript' };
+    headerRow.alignment = { vertical: 'bottom', horizontal: 'center' };
+    headerRow.outlineLevel = 1;
+    headerRow.commit();
+    lcomun++;
+  }
+
+  /**
+   * 导出内容
+   * @param data 
+   */
+  function setContent(data: ExcelData): void {
+    if (isEmpty(data)) return;
+    console.log(data,'zhe')
+    for (let h = 0; h < data.length; h++) {
+      let satarLcomun = lcomun;
+      let lcomunNow = worksheet.getRow(lcomun);
+      let hasMerge = false;
+      let starKey = 0;
+      let endKey = 0;
+      /** 循环列 */
+      //需要操作第几列
+      let sk = 0;
+      
+      for (let l = 0; l < data[h].length; l++) {
+        
+        if (Array.isArray(data[h][l])) {
+          //数组长度
+          starKey = sk;
+          hasMerge = true;
+          setArrayContent(data[h][l] as (string[])[], sk);
+          sk = sk + (data[h][l] as string[][])[0].length;
+          endKey = sk;
+         
+        } else {
+          //不是数组
+          lcomunNow.getCell(getLetter(sk)).value = data[h][l] as string;
+          lcomunNow.getCell(getLetter(sk)).border = {
+            top: { style: 'thin' },
+            left: { style: 'thin' },
+            bottom: { style: 'thin' },
+            right: { style: 'thin' }
+          };
+          lcomunNow.alignment = { vertical: 'middle', horizontal: 'center' };
+          sk++;
+        }
+      }
+      
+      if (hasMerge) setMergeLcomun(satarLcomun, lcomun, starKey, endKey);
+      lcomunNow.height = 25;
+      lcomunNow.commit();
+      lcomun++;
+    }
+  }
+
+  /**
+   * 占多行的数组
+   * @param arr 
+   * @param sk 
+   */
+  function setArrayContent(arr: string[][], sk: number): void {
+    /**
+     *  循环二维数组,在循环行  
+     */
+    let al = arr.length;
+    let sl = al - 1;
+    
+    for (let i = 0; i < arr.length; i++) {
+      let lcomunNow = worksheet.getRow(lcomun);
+      for(let v = 0; v < arr[i].length; v++) {
+        lcomunNow.getCell(getLetter(sk + v)).value = arr[i][v];
+        lcomunNow.getCell(getLetter(sk + v)).border = {
+          top: { style: 'thin' },
+          left: { style: 'thin' },
+          bottom: { style: 'thin' },
+          right: { style: 'thin' }
+        };
+        lcomunNow.alignment = { vertical: 'middle', horizontal: 'center' };
+      }
+      lcomunNow.height = 25;
+      lcomunNow.commit();
+      if (i < sl) lcomun++;
+    }
+  }
+
+  /**
+   *  合并操作
+   * @param satarLcomun 
+   * @param endLcomun 
+   * @param starKey 
+   * @param endKey 
+   */
+  function setMergeLcomun(
+    satarLcomun: number, 
+    endLcomun: number, 
+    starKey: number, 
+    endKey: number
+  ): void {
+    for(let ml = 0; ml < long; ml++) {
+      if (ml < starKey || ml >= endKey) {
+        worksheet.mergeCells(getLetter(ml) + satarLcomun + ':' + getLetter(ml) + endLcomun);
+      }
+    } 
+  }
+
+  /**
+   * 设置表末尾统计备注等
+   * @param footData 
+   */
+  function setFoot(footData: string | string[] | undefined): void {
+    if (isEmpty(footData)) return;
+    
+    if (Array.isArray(footData)) {
+      for (let f = 0; f < footData.length; f++) {
+        let lcomunNow = worksheet.getRow(lcomun);
+        lcomunNow.getCell(1).value = footData[f];
+        lcomunNow.getCell(1).border = {
+          top: { style: 'thin' },
+          left: { style: 'thin' },
+          bottom: { style: 'thin' },
+          right: { style: 'thin' }
+        };
+        lcomunNow.alignment = { vertical: 'middle', horizontal: 'left' };
+        worksheet.mergeCells('A' + lcomun + ':' + getLetter(long - 1) + lcomun);
+        lcomun++;
+      }
+    } else {
+      let lcomunNow = worksheet.getRow(lcomun);
+      lcomunNow.getCell(1).value = footData;
+      lcomunNow.getCell(1).border = {
+        top: { style: 'thin' },
+        left: { style: 'thin' },
+        bottom: { style: 'thin' },
+        right: { style: 'thin' }
+      };
+      lcomunNow.alignment = { vertical: 'middle', horizontal: 'left' };
+      worksheet.mergeCells('A' + lcomun + ':' + getLetter(long - 1) + lcomun);
+    }
+  }
+
+  /**
+   *  处理超过26个字母的列
+   * @param number 
+   * @returns 
+   */
+  function getLetter(number: number): string {
+    if (number < 26) {
+      return letter[number];
+    } else {
+      let n = number % 26;
+      let l = Math.floor(number / 26) - 1;
+      return letter[l] + letter[n];
+    }
+  }
+
+  /**
+   *  导出下载
+   * @param filename 
+   */
+  function saveAndDowloade(filename?: string): void {
+    const finalFilename = filename || new Date().getTime().toString();
+    
+    workBook.xlsx.writeBuffer().then(data => {
+      const blob = new Blob([data], { type: 'application/octet-stream' });
+      FileSaver.saveAs(blob, finalFilename + '.xlsx');
+    });
+  }
+
+  createSheets(sheets);
+  setTitle(title, long);
+  setHeader(header);
+  setContent(data);
+  setFoot(foot);
+  saveAndDowloade(filename);
+}

+ 2 - 2
src/views/Authorization/Role/Role.vue

@@ -112,11 +112,11 @@ const searchSchema = reactive<FormSchema[]>([
           value: ''
         },
         {
-          label: '不显示',
+          label: '启用',
           value: 0
         },
         {
-          label: '显示',
+          label: '禁用',
           value: 1
         }
       ]

+ 35 - 5
src/views/Authorization/User/User.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { reactive, ref, unref } from 'vue'
+import { reactive, ref, unref,onMounted } from 'vue'
 import {
   getUserRole,
   addUserRole,
@@ -19,6 +19,7 @@ import Write from './components/Write.vue'
 import Detail from './components/Detail.vue'
 import { Dialog } from '@/components/Dialog'
 import { BaseButton } from '@/components/Button'
+import { getRoleListApi } from '@/api/system/role'
 const { t } = useI18n()
 
 const { tableRegister, tableState, tableMethods } = useTable({
@@ -158,6 +159,11 @@ const searchSchema = reactive<FormSchema[]>([
       ]
     }
   },
+  {
+    field: 'type',
+    label: '',
+    value: 1,
+  },
   {
     field: 'name',
     label: '搜索',
@@ -169,7 +175,7 @@ const searchSchema = reactive<FormSchema[]>([
   }
 ])
 
-const searchParams = ref<{ status: number | string; name?: string }>({ status: '', name: '' })
+const searchParams = ref<{ status: number | string; name?: string;type: number }>({ status: '', name: '',type: 1 })
 const setSearchParams = (data: any) => {
   searchParams.value = data
   getList()
@@ -184,6 +190,18 @@ const saveLoading = ref(false)
 const action = (row: any, type: string) => {
   dialogTitle.value = t(type === 'edit' ? 'exampleDemo.edit' : 'exampleDemo.detail')
   actionType.value = type
+  let roles = [] as any[]
+  if (row.roles) {
+    row.roles.forEach(element => {
+      roleList.value.forEach((element1: any) => {
+        if (element == element1.label) {
+          roles.push(element1.value)
+        }
+      });
+    });
+  }
+  console.log(roles,'roles');
+  
   currentRow.value = {
     id: row.id,
     account: row.account, //账号
@@ -191,9 +209,10 @@ const action = (row: any, type: string) => {
     pwd: '',
     conf_pwd: '',
     phone: row.phone, //手机号
-    roles: row.roles, //角色数组
+    roles: roles, //角色数组
     status: row.status === 1 ? true : false ,//是否启用
-    is_all: row.status === 1 ?true: false
+    is_all: row.status === 1 ? true : false,
+    configure_id: row.configure_id
   }
   dialogVisible.value = true
 }
@@ -243,7 +262,8 @@ const save = async () => {
       phone: formData.phone, //手机号
       roles: formData.roles, //角色数组
       status: formData.status ? 1 : 0 ,//是否启用
-      is_all: formData.is_all ? 1: 0
+      is_all: formData.is_all ? 1 : 0,
+      configure_id: formData.configure_id
     }
     try {
       let res: any = {}
@@ -268,6 +288,16 @@ const save = async () => {
     }
   }
 }
+const roleList = ref([])
+onMounted(async () => { 
+  const re = await getRoleListApi({ page: 1, limit: 9999 })
+  roleList.value = re.data.list.map((res) => {
+    return {
+      label: res.role_name,
+      value: res.id
+    }
+  })
+})
 </script>
 
 <template>

+ 51 - 1
src/views/Authorization/User/components/Write.vue

@@ -6,6 +6,7 @@ import { useValidator } from '@/hooks/web/useValidator'
 import { cloneDeep } from 'lodash-es'
 import { getRoleListApi } from '@/api/system/role'
 import type { FormRules } from 'element-plus'
+import { getUnitList } from '@/api/goods'
 const { required, phone, lengthRange } = useValidator()
 
 const props = defineProps({
@@ -69,6 +70,11 @@ const formSchema = ref<FormSchema[]>([
       multiple: true
     }
   },
+  {
+    field: 'configure_id',
+    label: '管理区域',
+    component: 'Select'
+  },
   {
     field: 'status',
     label: '状态',
@@ -132,7 +138,11 @@ const rules = ref<FormRules<RuleForm>>({
   ],
   real_name: [required('请填写管理员姓名')]
 })
-
+interface op {
+  label: string
+  value: number
+}
+const areaList = ref<op[]>([])
 onMounted(async () => {
   const re = await getRoleListApi({ page: 1, limit: 9999 })
   roleList.value = re.data.list.map((res) => {
@@ -141,6 +151,27 @@ onMounted(async () => {
       value: res.id
     }
   })
+  const data1 = await getUnitList({ page: 1, limit: 100, type: 'area',pid: 0})
+
+  data1.data.list.forEach(element => {
+    if (element.children.length == 0) {
+      areaList.value.push({
+        value: element.id,
+        label: element.name,
+      })
+    } else {
+      areaList.value.push({
+        value: element.id,
+        label: element.name,
+      })
+      element.children.forEach(element1 => {
+        areaList.value.push({
+          value: element1.id,
+          label: '|__' + element1.name,
+        })
+      });
+    }
+  });
   if (props.currentRow) {
     rules.value.pwd = [
       {
@@ -153,6 +184,7 @@ onMounted(async () => {
       }
     ]
   }
+
 })
 
 const { formRegister, formMethods } = useForm()
@@ -169,6 +201,7 @@ const submit = async () => {
   }
 }
 
+
 watch(
   () => props.currentRow,
   async (value) => {
@@ -198,6 +231,23 @@ watch(
     immediate: true
   }
 )
+watch(
+  () => areaList,
+  async (value) => {
+    if (!value) return
+    setSchema([
+      {
+        field: 'configure_id',
+        path: 'componentProps.options',
+        value: value
+      }
+    ])
+  },
+  {
+    deep: true,
+    immediate: true
+  }
+)
 defineExpose({
   submit
 })

+ 368 - 110
src/views/Erp/Adjust/Adjust.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { reactive, ref, unref, onMounted} from 'vue'
+import { reactive, ref, unref, onMounted } from 'vue'
 import { useTable } from '@/hooks/web/useTable'
 import { useI18n } from '@/hooks/web/useI18n'
 import { Table, TableColumn } from '@/components/Table'
@@ -18,7 +18,9 @@ import {
   ElOption,
   ElForm,
   ElFormItem,
-  ElInput
+  ElInput,
+  ElTable,
+  ElTableColumn
 } from 'element-plus'
 import {
   getStoreUser,
@@ -40,8 +42,8 @@ const { tableRegister, tableState, tableMethods } = useTable({
   fetchDataApi: async () => {
     const res = await getAdjust({
       page: unref(currentPage) || 1,
-        limit: unref(pageSize) || 10,
-        ...unref(searchParams)
+      limit: unref(pageSize) || 10,
+      ...unref(searchParams)
     })
     return {
       list: res.data.data,
@@ -104,6 +106,71 @@ const getWare = async (query = '', id = '') => {
 const { dataList, loading, total, currentPage, pageSize } = tableState
 const { getList } = tableMethods
 
+const searchParams = ref<{
+  adjust_type?: string
+  wid?: string | number
+  store_id?: string | number
+}>({
+  adjust_type: '1',
+  store_id: '',
+  wid: ''
+})
+const setSearchParams = (data: any) => {
+  searchParams.value = data
+  getList()
+}
+
+const searchSchema = reactive<FormSchema[]>([
+  {
+    field: 'adjust_type',
+    label: '类型',
+    component: 'Select',
+    value: '1',
+    componentProps: {
+      placeholder: '仓库调价',
+      options: [
+        {
+          label: '仓库调价',
+          value: '1'
+        },
+        {
+          label: '门店调价',
+          value: '0'
+        }
+      ]
+    }
+  },
+  {
+    field: 'store_id',
+    label: '门店',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: storeOptions
+    }
+  },
+  {
+    field: 'wid',
+    label: '仓库',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: wareOptions
+    }
+  }
+  // {
+  //   field: 'name',
+  //   label: '名称',
+  //   component: 'Input',
+  //   value: '',
+  //   componentProps: {
+  //     placeholder: '请输入门店名称'
+  //   }
+  // }
+])
+
 const tableColumns = reactive<TableColumn[]>([
   {
     field: 'id',
@@ -113,7 +180,7 @@ const tableColumns = reactive<TableColumn[]>([
   },
   {
     field: 'order_id',
-    label: '报损单号',
+    label: '调价单号',
     minWidth: 230
   },
   {
@@ -122,52 +189,59 @@ const tableColumns = reactive<TableColumn[]>([
     minWidth: 150,
     slots: {
       default: ({ row }: any) => {
-        return <>{row.wid ? row.Warehouse?.name : row.store?.name}</>
+        console.log(row, 'row')
+        if (row.adjust_type == 1) {
+          return (
+            <>
+              <div>{row.Warehouse.name}</div>
+            </>
+          )
+        } else {
+          return (
+            <>
+              <div>{row.store?.name}</div>
+            </>
+          )
+        }
       }
     }
   },
   {
     field: 'stockinfo',
-    label: '出库商品',
+    label: '调价商品',
     minWidth: 200,
     slots: {
       default: ({ row }: any) => {
-        if (row?.stockinfo?.length > 0) {
-          return (
-            <>
-              {row.stockinfo.map((item) => {
-                return (
-                  <>
-                    <div>
-                      {item.product_name}
-                      <ElText class="mx-1" type="primary">
-                        {item.net_weight}
+        if (row?.body?.length > 0) {
+          if (row.store_id > 0) {
+            return (
+              <>
+                {row.body.map((item) => {
+                  return (
+                    <>
+                      <ElText class="mx-1 mr20" style={'margin-right: 10px'} type="primary">
+                        {item.product_name + ' '}
                       </ElText>
-                      {item.suk}
-                    </div>
-                  </>
-                )
-              })}
-            </>
-          )
-        } else if (row?.info?.length > 0) {
-          return (
-            <>
-              {row.info.map((item) => {
-                return (
-                  <>
-                    <div>
-                      {item.product_name}
-                      <ElText class="mx-1" type="primary">
-                        {item.net_weight}
+                    </>
+                  )
+                })}
+              </>
+            )
+          } else {
+            return (
+              <>
+                {row.body.map((item) => {
+                  return (
+                    <>
+                      <ElText class="mx-1 " style={'margin-right: 10px'} type="primary">
+                        {item.product_name}
                       </ElText>
-                      {item.suk}
-                    </div>
-                  </>
-                )
-              })}
-            </>
-          )
+                    </>
+                  )
+                })}
+              </>
+            )
+          }
         } else {
           return <></>
         }
@@ -245,80 +319,19 @@ const tableColumns = reactive<TableColumn[]>([
             </>
           )
         } else {
-          return <></>
+          return (
+            <>
+              <BaseButton link size="small" type="primary" onClick={() => action('info', row)}>
+                详情
+              </BaseButton>
+            </>
+          )
         }
       }
     }
   }
 ])
 
-const searchParams = ref<{
-  adjust_type?: string
-  wid?: string | number
-  store_id?: string | number
-}>({
-  adjust_type: '1',
-  store_id: '',
-  wid: ''
-})
-const setSearchParams = (data: any) => {
-  searchParams.value = data
-  getList()
-}
-
-const searchSchema = reactive<FormSchema[]>([
-  {
-    field: 'adjust_type',
-    label: '类型',
-    component: 'Select',
-    value: '1',
-    componentProps: {
-      placeholder: '门店调价',
-      options: [
-        {
-          label: '仓库报损',
-          value: '1'
-        },
-        {
-          label: '门店调价',
-          value: '0'
-        }
-      ]
-    }
-  },
-  {
-    field: 'store_id',
-    label: '门店',
-    component: 'Select',
-    value: '',
-    componentProps: {
-      placeholder: '请选择',
-      options: storeOptions
-    }
-  },
-  {
-    field: 'wid',
-    label: '仓库',
-    component: 'Select',
-    value: '',
-    componentProps: {
-      placeholder: '请选择',
-      options: wareOptions
-    }
-  }
-  // {
-  //   field: 'name',
-  //   label: '名称',
-  //   component: 'Input',
-  //   value: '',
-  //   componentProps: {
-  //     placeholder: '请输入门店名称'
-  //   }
-  // }
-])
-
-
-
 const dialogVisible = ref(false)
 const currentRow = ref()
 const dialogTitle = ref('')
@@ -339,10 +352,60 @@ const dialogVisibles = ref(false)
 const dialogVisibless = ref(false)
 const dialogVisiblesss = ref(false)
 const dialogVisiblessss = ref(false)
+const showInfo = ref(false)
 
 const endItem = ref({ wid: '', store_id: '', info: [], out_order_id: '', id: 0 })
+type storeOrWare = {
+  name?: string
+  phone?: number | string
+}
+type bodyGood = {
+  product_id: number | string
+}
+type adminInfo = {
+  real_name: string
+}
+type adjustItem = {
+  Warehouse?: storeOrWare
+  add_time?: number
+  adjust_type?: number
+  auser?: adminInfo
+  auth_admin_id?: number
+  auth_remark?: null | string
+  auth_time?: number
+  body: bodyGood[]
+  create_admin_id?: number
+  cuser?: adminInfo
+  id: number
+  order_id?: string
+  status: number
+  store?: storeOrWare
+  store_id?: number
+  type: number
+  wid?: number
+}
+const adItem = ref<adjustItem>({
+  Warehouse: {},
+  adjust_type: 0,
+  auth_admin_id: 0,
+  auth_remark: null,
+  auth_time: 0,
+  body: [],
+  create_admin_id: 0,
+  id: 0,
+  order_id: '',
+  status: 0,
+  store: {},
+  store_id: 0,
+  type: 0,
+  wid: 0
+})
 const action = async (type: string, row?: any) => {
   actionType.value = type
+  if (type == 'info') {
+    adItem.value = row
+    showInfo.value = true
+  }
   if (type == 'repass') {
     endItem.value = row
     dialogVisibless.value = true
@@ -426,8 +489,8 @@ const action = async (type: string, row?: any) => {
       roles: row.roles * 1
     }
     console.log(currentRow, 'currentRow')
+    dialogVisible.value = true
   }
-  dialogVisible.value = true
 }
 const formData = ref({ auth_admin_id: '', auth_status: 1, freight: '', refuse_remark: '' })
 const adminOptions = ref<any[]>([])
@@ -616,4 +679,199 @@ const confirmClicks = async () => {
       </div>
     </template>
   </Dialog>
+  <Dialog v-model="showInfo" title="调价" width="900px">
+    <div id="dc">
+      <div class="section">
+        <div class="text-center title pb5">调价详情</div>
+        <div class="top-tit">
+          <div class="item mb10">
+            <div class=""
+              ><span class="name">调价单号:</span><span>{{ adItem.order_id }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="adItem?.wid && adItem?.Warehouse?.name">
+            <div class=""
+              ><span class="name">调价单位:</span
+              ><span>{{ adItem.Warehouse.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="adItem?.wid">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ adItem.Warehouse?.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="adItem?.store_id">
+            <div class=""
+              ><span class="name">调价单位:</span><span>{{ adItem?.store?.name }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item  mb10" v-if="adItem?.store">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ adItem?.store?.phone }}</span></div
+            >
+          </div>
+        </div>
+        <div class="" v-if="adItem?.wid">
+          <ElTable :data="adItem.body" style="width: 100%" :border="true">
+            <el-table-column label="id" prop="product_id" />
+            <el-table-column label="商品名称" prop="product_name" />
+            <el-table-column label="价格" prop="price" />
+          </ElTable>
+        </div>
+        <div class="" v-if="adItem?.store_id">
+          <ElTable :data="adItem.body" style="width: 100%" :border="true">
+            <ElTableColumn type="expand">
+              <template #default="props">
+                <div m="4" class="pl20">
+                  <ElTable :data="props.row.specs" :border="true">
+                    <ElTableColumn label="单位" prop="name" />
+                    <ElTableColumn label="价格" prop="price" />
+                    <ElTableColumn label="VIP价格" prop="price_1" />
+                    <ElTableColumn label="金卡价格" prop="price_2" />
+                    <ElTableColumn label="钻卡价格" prop="price_3" />
+                  </ElTable>
+                </div>
+              </template>
+            </ElTableColumn>
+            <el-table-column label="id" prop="product_id" />
+            <el-table-column label="商品名称" prop="product_name" />
+          </ElTable>
+        </div>
+        <div class="btm-tip">
+          <div class="itemt">
+            <span class="name">货品数:</span>
+            <span>{{ adItem.body.length }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">创建人:</span>
+            <span>{{ adItem?.cuser?.real_name }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">审核人:</span>
+            <span>{{ adItem?.auser?.real_name }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- <template #footer>
+      <div style="flex: auto">
+        <BaseButton type="primary" v-print="printobj">打印</BaseButton>
+      </div>
+    </template> -->
+  </Dialog>
 </template>
+
+<style>
+@media print {
+  .section {
+    page-break-before: always;
+    margin-top: 0;
+  }
+}
+.bold {
+  font-weight: bold;
+}
+#dc {
+  font-size: 14px;
+  page-break-before: always;
+  padding: 10px;
+  position: relative;
+  padding-bottom: 100px;
+}
+.title {
+  font-size: 18px;
+  font-weight: bold;
+  color: #000000;
+}
+.top-tit {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+  padding: 20px 0 10px;
+}
+.item {
+  width: 50%;
+  /* margin-bottom: 10px; */
+}
+.mb10 {
+  margin-bottom: 10px;
+}
+.items {
+  width: 100% !important;
+}
+.name {
+  font-weight: bold;
+  color: #000000;
+}
+.table {
+  width: 98%;
+  text-align: center;
+  border-top: 1px solid #000;
+  /* border-left: 1px solid #000; */
+}
+.table > .tr {
+  display: flex;
+  flex-wrap: wrap;
+}
+.table .tr > .item {
+  padding: 5px 10px;
+  /* border-right: 1px solid #000; */
+  border-bottom: 1px solid #000;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.w30 {
+  width: 30%;
+}
+.w20 {
+  width: 20%;
+}
+.w10 {
+  width: 10%;
+}
+.w5 {
+  width: 5%;
+}
+.w15 {
+  width: 15%;
+}
+.table .th {
+  color: #000000;
+  padding: 10px 0;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+  min-width: 60px;
+}
+
+.table .td {
+  padding: 5px 3px;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+}
+@media print {
+  body,
+  html,
+  .previewPageBox {
+    height: auto !important;
+    overflow: visible !important;
+  }
+
+  .previewPageBox {
+    position: relative !important;
+  }
+}
+.btm-tip {
+  display: flex;
+  width: 100%;
+  flex-wrap: wrap;
+  padding-top: 150px;
+}
+.btm-tip .itemt {
+  width: 33.3%;
+  margin-bottom: 10px;
+}
+</style>

+ 42 - 24
src/views/Erp/Adjust/AdjustEdit.vue

@@ -20,12 +20,7 @@ import {
   ElCard
 } from 'element-plus'
 import { useRoute, useRouter } from 'vue-router'
-import {
-  getStoreList,
-  getStoreUser,
-  getOutGood,
-  getStoreGood,
-  addWareAdjust} from '@/api/erp'
+import { getStoreList, getStoreUser, getOutGood, getStoreGood, addWareAdjust } from '@/api/erp'
 const pageTitle = ref('添加')
 const { params } = useRoute()
 const { push } = useRouter()
@@ -50,13 +45,11 @@ const hzBuild = reactive<{ [key: string]: any }>({
   rate: ''
 })
 
-
-
 const rules = reactive({
   rate: [{ required: true, message: '请输入调价比例', trigger: 'change' }],
   create_admin_id: [{ required: true, message: '请选择创建人', trigger: 'change' }],
   wid: [{ required: true, message: '请选择仓库', trigger: 'change' }],
-  store_id: [{ required: true, message: '请选择门店', trigger: 'change' }],
+  store_id: [{ required: true, message: '请选择门店', trigger: 'change' }]
 })
 const formRef = ref<FormInstance>()
 const formRefs = ref<FormInstance>()
@@ -67,13 +60,14 @@ const goSuccess = () => {
     confirmButtonText: '返回列表',
     cancelButtonText: `继续创建`,
     type: 'warning'
-  }).then(() => {
-    backList()
-    
-  }).catch(() => {
-    checkGoods.value = []
-    checkGoodss.value = []
   })
+    .then(() => {
+      backList()
+    })
+    .catch(() => {
+      checkGoods.value = []
+      checkGoodss.value = []
+    })
 }
 
 /**
@@ -100,18 +94,24 @@ const save = async (formEl: FormInstance | undefined) => {
     if (actinoTabIndex.value == 1) {
       let good: any[] = []
       try {
+        console.log(checkGoods.value, 'checkGoods.value')
+
         checkGoods.value.forEach((item) => {
+          console.log(item, 'item')
+
           let obj = {
             ot_price: item.out_price || 0,
             price: selfBuild.type == 1 ? item.price : showPrice(item.out_price || 0),
             product_id: item.product_id,
-            product_name: item.prodcut_name
+            product_name: item.product_name
           }
           if (selfBuild.type == 0) {
             Object.assign(obj, { scale: selfBuild.rate })
           }
           good.push(obj)
         })
+        console.log(good, 'good')
+
         const res = await addWareAdjust({
           body: good,
           create_admin_id: selfBuild.create_admin_id,
@@ -142,7 +142,13 @@ const save = async (formEl: FormInstance | undefined) => {
             price: hzBuild.type == 1 ? item.price : showPrices(item.prices),
             product_id: item.id,
             product_name: item.store_name,
-            specs: item.specs
+            specs: item.specs.map(items => {
+              delete items.prices
+              delete items.prices_1
+              delete items.prices_2
+              delete items.prices_3
+              return items
+            })
           }
           if (hzBuild.type == 0) {
             Object.assign(obj, { scale: hzBuild.rate })
@@ -153,6 +159,8 @@ const save = async (formEl: FormInstance | undefined) => {
         //   if (!ok) {
         //     return
         //   }
+
+
         const res = await addWareAdjust({
           body: good,
           create_admin_id: hzBuild.create_admin_id,
@@ -284,12 +292,19 @@ const confirmClick = () => {
     if (actinoTabIndex.value == 1) {
       item.price = +item.out_price || 0
     } else {
-      item.prices = item.price
-      item.prices_3 = item.price_3
-      item.prices_2 = item.price_2
-      item.prices_1 = item.price_1
+      // item.prices = item.price
+      // item.prices_3 = item.price_3
+      // item.prices_2 = item.price_2
+      // item.prices_1 = item.price_1
+      item.specs.map((items) => {
+        items.prices = items.price
+        items.prices_3 = items.price_3
+        items.prices_2 = items.price_2
+        items.prices_1 = items.price_1
+        return items
+      })
     }
-    console.log(item)
+    console.log(item, 'item----------')
     return item
   })
   if (actinoTabIndex.value == 1) {
@@ -380,6 +395,9 @@ const showPrices = (price) => {
     return ((price * (100 + hzBuild.rate * 1)) / 100).toFixed(2) + ''
   }
 }
+const delCheckGoodss = (index: number) => {
+  checkGoodss.value.splice(index, 1)
+}
 </script>
 <template>
   <ContentWrap
@@ -521,7 +539,7 @@ const showPrices = (price) => {
               <ElRadio :label="0" size="large">比例调整</ElRadio>
             </ElRadioGroup>
           </ElFormItem>
-          <ElFormItem label="比例" v-if="hzBuild.type == 0" prop="rate">
+          <ElFormItem label="比例 (%)" v-if="hzBuild.type == 0" prop="rate">
             <ElInput type="number" v-model="hzBuild.rate" />
           </ElFormItem>
           <ElFormItem label="创建人员" prop="create_admin_id" v-if="hzBuild.store_id">
@@ -640,7 +658,7 @@ const showPrices = (price) => {
                   </template>
                 </ElTable>
                 <template #footer>
-                  <BaseButton type="primary" link style="margin-bottom: 20px"> 删除 </BaseButton>
+                  <BaseButton type="primary" link style="margin-bottom: 20px" @click="delCheckGoodss(index)"> 删除 </BaseButton>
                 </template>
               </ElCard>
             </div>

+ 2 - 2
src/views/Erp/Check/CheckEdit.vue

@@ -477,9 +477,9 @@ const delCheckGoodss = (row) => {
               />
             </ElSelect>
           </ElFormItem>
-          <ElFormItem label="调价商品">
+          <ElFormItem label="商品">
             <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1, '')">
-              调价商品
+              选择商品
             </BaseButton>
             <ElTable
               header-cell-class-name="bg-gray-100!"

+ 240 - 3
src/views/Erp/Losses/Losses.vue

@@ -254,10 +254,17 @@ const tableColumns = reactive<TableColumn[]>([
               <BaseButton link size="small" type="danger" onClick={() => action('repass', row)}>
                 拒绝
               </BaseButton>
+              <ElDivider direction="vertical" />
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton>
             </>
           )
         } else {
-          return <></>
+          return <>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton></>
         }
       }
     }
@@ -265,10 +272,10 @@ const tableColumns = reactive<TableColumn[]>([
 ])
 
 const searchParams = ref<{
-  type?: string
+  // type?: string
   qtype?: string
 }>({
-  type: 'loss',
+  // type: 'loss',
   qtype: 'store'
 })
 const setSearchParams = (data: any) => {
@@ -349,10 +356,16 @@ const dialogVisibles = ref(false)
 const dialogVisibless = ref(false)
 const dialogVisiblesss = ref(false)
 const dialogVisiblessss = ref(false)
+const prDialogVisible = ref(false)
+const prItem = ref<any>({})
 
 const endItem = ref({ wid: '', store_id: '', info: [], out_order_id: '', id: 0 })
 const action = async (type: string, row?: any) => {
   actionType.value = type
+  if (type == 'print') {
+    prDialogVisible.value = true
+    prItem.value = row
+  }
   if (type == 'repass') {
     endItem.value = row
     dialogVisibless.value = true
@@ -543,6 +556,33 @@ const confirmClicks = async () => {
     cancelClicks()
   }
 }
+
+const getTime = () => {
+  let time = new Date().getTime()
+  return formatTime(time, 'yyyy-MM-dd HH:mm:ss')
+}
+const getLen = () => {
+  let sum = 0
+  prItem.value.stockinfo.forEach((item) => {
+      sum += item.net_weight * 1
+  })
+  return sum
+}
+const printobj = ref({
+  id: 'dc',
+  popTitle: '好的打印标题',
+  extraCss:
+    'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css',
+  extraHead: '<meta http-equiv="content-language" content="zh-cn" />',
+  beforeOpenCallback(vue) {
+    vue.printLoading = true
+    console.log('打开之前')
+  },
+  openCallback(vue) {
+    vue.printLoading = false
+    console.log('执行了打印')
+  }
+})
 </script>
 
 <template>
@@ -626,4 +666,201 @@ const confirmClicks = async () => {
       </div>
     </template>
   </Dialog>
+  <Dialog v-model="prDialogVisible" title="打印">
+    <div id="dc">
+      <div class="section">
+        <div class="text-center title">报损单</div>
+        <div class="top-tit">
+          <div class="item mb10">
+            <div class=""
+              ><span class="name">报损单号:</span><span>{{ prItem.order_id }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.store && prItem.store.name">
+            <div class=""
+              ><span class="name">报损单位:</span><span>{{ prItem?.store.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.ware && prItem.ware.name">
+            <div class=""
+              ><span class="name">报损单位:</span><span>{{ prItem?.ware.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.store.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.ware.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item items mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">地址:</span><span>{{ prItem.store.address }}</span></div
+            >
+          </div>
+        </div>
+        <div class="table">
+          <div class="tr">
+            <div class="item w10">序号</div>
+            <div class="item w20">编号</div>
+            <div class="item w30">商品</div>
+            <div class="item w20">数量</div>
+            <div class="item w20">单位</div>
+          </div>
+          <div class="tr" v-for="(item, index) in prItem.stockinfo">
+            <div class="item w10">{{ index + 1 }}</div>
+            <div class="item w20">{{ item.bar_code }}</div>
+            <div class="item w30">{{ item.product_name }}</div>
+            <div class="item w20">{{
+              item.net_weight}}</div>
+            <div class="item w20">{{ item.suk }}</div>
+          </div>
+        </div>
+        <div class="btm-tip">
+          <div class="itemt">
+            <span class="name">货品数:</span>
+            <span>{{ prItem.stockinfo.length }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">数量:</span>
+            <span>{{ getLen() }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">审核人:</span>
+            <span>{{ prItem.auth_admin_id ? prItem.auser.real_name : '' }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">仓管员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span class="name">财务员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span>打印时间:</span>
+            <span>{{ getTime() }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <template #footer>
+      <div style="flex: auto">
+        <BaseButton type="primary" v-print="printobj">打印</BaseButton>
+      </div>
+    </template>
+  </Dialog>
 </template>
+<style>
+@media print {
+  .section {
+    page-break-before: always;
+    margin-top: 0;
+  }
+}
+.bold {
+  font-weight: bold;
+}
+#dc {
+  font-size: 14px;
+  page-break-before: always;
+  padding: 10px;
+  position: relative;
+  padding-bottom: 100px;
+}
+.title {
+  font-size: 18px;
+  font-weight: bold;
+  color: #000000;
+}
+.top-tit {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+  padding: 20px 0 10px;
+}
+.item {
+  width: 50%;
+  /* margin-bottom: 10px; */
+}
+.mb10 {
+  margin-bottom: 10px;
+}
+.items {
+  width: 100% !important;
+}
+.name {
+  font-weight: bold;
+  color: #000000;
+}
+.table {
+  width: 98%;
+  text-align: center;
+  border-top: 1px solid #000;
+  /* border-left: 1px solid #000; */
+}
+.table > .tr {
+  display: flex;
+  flex-wrap: wrap;
+}
+.table .tr > .item {
+  padding: 5px 10px;
+  /* border-right: 1px solid #000; */
+  border-bottom: 1px solid #000;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.w30 {
+  width: 30%;
+}
+.w20 {
+  width: 20%;
+}
+.w10 {
+  width: 10%;
+}
+.table .th {
+  color: #000000;
+  padding: 10px 0;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+  min-width: 60px;
+}
+
+.table .td {
+  padding: 5px 3px;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+}
+@media print {
+  body,
+  html,
+  .previewPageBox {
+    height: auto !important;
+    overflow: visible !important;
+  }
+
+  .previewPageBox {
+    position: relative !important;
+  }
+}
+.btm-tip {
+  display: flex;
+  width: 100%;
+  flex-wrap: wrap;
+  padding-top: 150px;
+  
+}
+.btm-tip .itemt {
+  width: 33.3%;
+  margin-bottom: 10px;
+}
+</style>
+

+ 3 - 3
src/views/Erp/Losses/LossesEdit.vue

@@ -499,7 +499,7 @@ const delCheckGoodss = (row) => {
               />
             </ElSelect>
           </ElFormItem>
-          <ElFormItem label="出库商品">
+          <ElFormItem label="报损商品">
             <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1, '')">
               选择商品
             </BaseButton>
@@ -600,9 +600,9 @@ const delCheckGoodss = (row) => {
               />
             </ElSelect>
           </ElFormItem>
-          <ElFormItem label="调价商品">
+          <ElFormItem label="报损商品">
             <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1, '')">
-              调价商品
+              添加商品
             </BaseButton>
             <ElTable
               header-cell-class-name="bg-gray-100!"

+ 426 - 110
src/views/Erp/Out/Out.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { reactive, ref, unref } from 'vue'
+import { reactive, ref, unref,onMounted } from 'vue'
 import { useTable } from '@/hooks/web/useTable'
 import { useI18n } from '@/hooks/web/useI18n'
 import { Table, TableColumn } from '@/components/Table'
@@ -26,7 +26,17 @@ import {
   ElInput,
   ElDatePicker
 } from 'element-plus'
-import { getStoreUser, delPur,endPur ,upCompute,authComput,getOut,outAuth,outOut} from '@/api/erp'
+import {
+  getStoreUser,
+  endPur,
+  upCompute,
+  authComput,
+  getOut,
+  outAuth,
+  outOut,
+  delOut,
+  getStoreList
+} from '@/api/erp'
 import { useRouter } from 'vue-router'
 import { formatTime } from '@/utils'
 import { endPuritem } from '@/api/erp/types'
@@ -42,10 +52,7 @@ const { tableRegister, tableState, tableMethods } = useTable({
       limit: unref(pageSize) || 10,
       ...unref(searchParams)
     })
-    return {
-      list: res.data.data,
-      total: res.data.count || 0
-    }
+    return { list: res.data.data, total: res.data.count || 0 }
   }
 })
 
@@ -53,30 +60,17 @@ const { dataList, loading, total, currentPage, pageSize } = tableState
 const { getList } = tableMethods
 
 const tableColumns = reactive<TableColumn[]>([
-  {
-    field: 'id',
-    label: 'ID',
-    align: 'center',
-    width: 70
-  },
-  {
-    field: 'out_order_id',
-    label: '出库单号',
-    minWidth: 230
-  },
-  {
-    field: 'total_price',
-    label: '总价格',
-    minWidth: 150
-  },
- 
+  { field: 'id', label: 'ID', align: 'center', width: 70 },
+  { field: 'out_order_id', label: '出库单号', minWidth: 230 },
+  { field: 'total_price', label: '总价格', minWidth: 150 },
+
   {
     field: 'in',
     label: '调出单位',
     minWidth: 150,
     slots: {
       default: ({ row }: any) => {
-        return <>{row.up_store_id ? row.tstore?.name : (row.up_wid? row.tware?.name: '')}</>
+        return <>{row.up_store_id ? row.tstore?.name : row.up_wid ? row.tware?.name : ''}</>
       }
     }
   },
@@ -104,7 +98,7 @@ const tableColumns = reactive<TableColumn[]>([
                   <div>
                     {item.product_name}
                     <ElText class="mx-1" type="primary">
-                      {item.is_weigh == 1? item.net_weight:item.product_num * 1}
+                      {item.is_weigh == 1 ? item.net_weight : item.product_num * 1}
                     </ElText>
                     {item.suk}
                   </div>
@@ -125,7 +119,7 @@ const tableColumns = reactive<TableColumn[]>([
         return (
           <>
             <div>{row.cuser?.real_name || '-'}</div>
-            <div>{row.create_time?formatTime(row.create_time*1000,'yyyy-MM-dd'): ''}</div>
+            <div>{row.create_time ? formatTime(row.create_time * 1000, 'yyyy-MM-dd') : ''}</div>
           </>
         )
       }
@@ -140,7 +134,7 @@ const tableColumns = reactive<TableColumn[]>([
         return (
           <>
             <div>{row.auser?.real_name || '-'}</div>
-            <div>{row.auth_time?formatTime(row.auth_time*1000,'yyyy-MM-dd'): ''}</div>
+            <div>{row.auth_time ? formatTime(row.auth_time * 1000, 'yyyy-MM-dd') : ''}</div>
           </>
         )
       }
@@ -161,10 +155,10 @@ const tableColumns = reactive<TableColumn[]>([
         } else if (row.status == 2 && row.auth_status == -2) {
           return (
             <>
-  <ElTag type="danger">收货拒绝</ElTag>
+              <ElTag type="danger">收货拒绝</ElTag>
             </>
           )
-         } else{
+        } else {
           return (
             <>
               <ElTag
@@ -216,25 +210,112 @@ const tableColumns = reactive<TableColumn[]>([
               <BaseButton link size="small" type="danger" onClick={() => delAction(row)}>
                 删除
               </BaseButton>
+              <ElDivider direction="vertical" />
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton>
             </>
           )
-        } else if(  row.status == 1 ){
+        } else if (row.status == 1) {
           return (
             <>
               <BaseButton link size="small" type="primary" onClick={() => action('out', row)}>
                 出库
               </BaseButton>
+              <ElDivider direction="vertical" />
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton>
             </>
           )
         } else {
-          return (<></>)
+          return (
+            <>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton>
+            </>
+          )
         }
       }
     }
   }
 ])
-
+const storeLoading = ref(false)
+const wareLoading = ref(false)
+const storeOptions = ref<any[]>([])
+const wareOptions = ref<any[]>([])
+  const getStore = async (query = '', id = '') => {
+  try {
+    storeLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, store: 1 })
+    if (res) {
+      storeOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    storeLoading.value = false
+  }
+}
+const getWare = async (query = '', id = '') => {
+  try {
+    wareLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, type: 3 })
+    if (res) {
+      wareOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    wareLoading.value = false
+  }
+}
 const searchSchema = reactive<FormSchema[]>([
+   {
+    field: 'out_order_id',
+    label: '出库单号',
+    component: 'Input',
+    value: '',
+    componentProps: {
+      placeholder: '请输入出库单号'
+    }
+  },
+
+  {
+    field: 'store_id',
+    label: '门店',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: storeOptions
+    }
+  },
+  {
+    field: 'wid',
+    label: '仓库',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: wareOptions
+    }
+  },
   {
     field: 'status',
     label: '状态',
@@ -243,31 +324,15 @@ const searchSchema = reactive<FormSchema[]>([
     componentProps: {
       placeholder: '全部',
       options: [
-        {
-          label: '待审核',
-          value: '0'
-        },
-        {
-          label: '出库审核',
-          value: '1'
-        }
+        { label: '待审核', value: '0' },
+        { label: '出库审核', value: '1' }
       ]
     }
   },
-  // {
-  //   field: 'name',
-  //   label: '名称',
-  //   component: 'Input',
-  //   value: '',
-  //   componentProps: {
-  //     placeholder: '请输入门店名称'
-  //   }
-  // }
+ 
 ])
 
-const searchParams = ref<{
-  status?: string
-}>({
+const searchParams = ref<{ status?: string }>({
   // status: '3'
 })
 const setSearchParams = (data: any) => {
@@ -295,33 +360,33 @@ const dialogVisibles = ref(false)
 const dialogVisibless = ref(false)
 const dialogVisiblesss = ref(false)
 const dialogVisiblessss = ref(false)
+const prDialogVisible = ref(false)
+const prItem = ref<any>({})
 
-const endItem = ref<endPuritem>({
-  purchasing_person_admin_id: 0,
-  id: 0,
-  info: []
-})
+
+const endItem = ref<endPuritem>({ purchasing_person_admin_id: 0, id: 0, info: [] })
 const action = async (type: string, row?: any) => {
   actionType.value = type
+  if (type == 'print') {
+    console.log(row)
+
+    prDialogVisible.value = true
+    prItem.value = row
+  }
   if (type == 'out') {
     ElMessageBox.confirm('是否立即出库?', {
-    confirmButtonText: '确认',
-    cancelButtonText: '取消',
-    type: 'warning'
-  })
-    .then(async () => {
-      const re = await outOut(row.id)
-      if (re) {
-        ElMessage({
-          showClose: true,
-          message: '出库成功',
-          type: 'success'
-        })
-      }
-      await getList()
+      confirmButtonText: '确认',
+      cancelButtonText: '取消',
+      type: 'warning'
     })
-    .catch(() => {})
-
+      .then(async () => {
+        const re = await outOut(row.id)
+        if (re) {
+          ElMessage({ showClose: true, message: '出库成功', type: 'success' })
+        }
+        await getList()
+      })
+      .catch(() => {})
   }
   if (type == 'authCompute') {
     endItem.value = row
@@ -400,13 +465,9 @@ const delAction = (row: any) => {
     type: 'warning'
   })
     .then(async () => {
-      const re = await delPur(row.id)
+      const re = await delOut(row.id)
       if (re) {
-        ElMessage({
-          showClose: true,
-          message: '删除成功',
-          type: 'success'
-        })
+        ElMessage({ showClose: true, message: '删除成功', type: 'success' })
       }
       await getList()
     })
@@ -428,10 +489,7 @@ const getAdmin = async () => {
   try {
     if (res) {
       adminOptions.value = res.data.map((item) => {
-        return {
-          value: item.id,
-          label: item.real_name
-        }
+        return { value: item.id, label: item.real_name }
       })
       console.log(adminOptions.value, 'adminOptions.value')
     } else {
@@ -452,11 +510,7 @@ const cancelClicks = () => {
   dialogVisibless.value = false
   authId.value = 0
   storeId.value = 0
-  endItem.value = {
-    id: 0,
-    purchasing_person_admin_id:0,
-    info: []
-  }
+  endItem.value = { id: 0, purchasing_person_admin_id: 0, info: [] }
 }
 const confirmClick = async () => {
   if (!formData.value.auth_admin_id) {
@@ -480,10 +534,10 @@ const confirmClicks = async () => {
     purchasing_person_admin_id: endItem.value.purchasing_person_admin_id,
     info: []
   }
-  qdata.info = endItem.value.info.map(item => {
+  qdata.info = endItem.value.info.map((item) => {
     if (item.is_weigh == 1) {
       item.tare_weight = item.tare_weight_one * 1 * item.pur_num * 1
-      item.net_weight = item.weight*1 - item.tare_weight
+      item.net_weight = item.weight * 1 - item.tare_weight
     }
     return item
   })
@@ -495,7 +549,7 @@ const confirmClicks = async () => {
   }
 }
 const confirmClickss = async () => {
-  const res = await upCompute(endItem.value.id,{
+  const res = await upCompute(endItem.value.id, {
     prove: compteData.value.image[0],
     pay_time: new Date(compteData.value.pay_time).getTime() / 1000
   })
@@ -507,12 +561,8 @@ const confirmClickss = async () => {
 }
 const cancelClickss = () => {
   dialogVisiblesss.value = false
-  endItem.value = {
-    id: 0,
-    purchasing_person_admin_id:0,
-    info: []
-  }
-  compteData.value = {image: [],pay_time: ''}
+  endItem.value = { id: 0, purchasing_person_admin_id: 0, info: [] }
+  compteData.value = { image: [], pay_time: '' }
 }
 const compteData = ref({ image: [], pay_time: '' })
 const authCompteData = ref({ pay_status: 2 })
@@ -527,13 +577,69 @@ const confirmClicksss = async () => {
 }
 const cancelClicksss = () => {
   dialogVisiblessss.value = false
-  endItem.value = {
-    id: 0,
-    purchasing_person_admin_id:0,
-    info: []
+  endItem.value = { id: 0, purchasing_person_admin_id: 0, info: [] }
+  authCompteData.value = { pay_status: 2 }
+}
+const printobj = ref({
+  id: 'dc',
+  popTitle: '好的打印标题',
+  extraCss:
+    'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css',
+  extraHead: '<meta http-equiv="content-language" content="zh-cn" />',
+  beforeOpenCallback(vue) {
+    vue.printLoading = true
+    console.log(window.document.body.style, 'window.document.body.innerHTML')
+
+    console.log('打开之前')
+  },
+  openCallback(vue) {
+    vue.printLoading = false
+    console.log('执行了打印')
   }
-  authCompteData.value = {pay_status: 2}
+})
+const printing = () => {
+  // const splitDoms = document.getElementsByClassName('pri')
+  // console.log(splitDoms)
+  // let startY = 0 // 占用A4纸的高度,从每页第一个poetry div的top值开始累加
+  // for (let i = 0; i < splitDoms.length; i++) {
+  //     const splitDom = splitDoms[i]
+  //     const splitValue = splitDom.getBoundingClientRect()
+  //     console.log(splitDom.getBoundingClientRect())
+  //     if (startY === 0) {
+  //         startY = splitValue.top
+  //     }
+  //     const pageHeight = splitValue.bottom - startY
+  //     // 当加上当前div的高度大于A4纸高度时,给前一个div加上分页标识
+  //     if (pageHeight > PAGE_HEIGHT) {
+  //         console.log(i)
+  //         startY = 0
+  //         if (i > 0) {
+  //             splitDoms[i - 1].style.pageBreakBefore = 'always'; // 给前一个元素添加分页符
+  //         }
+  //     }
+  // }
+}
+const getTime = () => {
+  let time = new Date().getTime()
+  return formatTime(time, 'yyyy-MM-dd HH:mm:ss')
+}
+const getLen = () => {
+  let sum = 0
+  prItem.value.info.forEach((item) => {
+    console.log(item.product_num)
+    if (item.is_weigh == 1) {
+      sum += item.net_weight * 1
+    } else {
+      sum += item.product_num * 1
+    }
+  })
+  return sum
 }
+
+onMounted(() => {
+  getStore()
+  getWare()
+})
 </script>
 
 <template>
@@ -552,9 +658,7 @@ const cancelClicksss = () => {
       :data="dataList"
       :loading="loading"
       @register="tableRegister"
-      :pagination="{
-        total
-      }"
+      :pagination="{ total }"
     />
   </ContentWrap>
   <Dialog v-model="dialogVisibles" :title="dialogTitle" width="500px" maxHeight="160px">
@@ -663,11 +767,7 @@ const cancelClicksss = () => {
         <UpImgButtom v-model="compteData.image"></UpImgButtom>
       </ElFormItem>
       <ElFormItem label="支付时间" prop="status">
-        <ElDatePicker
-        v-model="compteData.pay_time"
-        type="date"
-        placeholder="请选择支付时间"
-      />
+        <ElDatePicker v-model="compteData.pay_time" type="date" placeholder="请选择支付时间" />
       </ElFormItem>
     </ElForm>
     <template #footer>
@@ -693,4 +793,220 @@ const cancelClicksss = () => {
       </div>
     </template>
   </Dialog>
+  <Dialog v-model="prDialogVisible" title="打印">
+    <div id="dc">
+      <div class="section">
+        <div class="text-center title">调出单</div>
+        <div class="top-tit">
+          <div class="item mb10">
+            <div class=""
+              ><span class="name">出库单号:</span><span>{{ prItem.out_order_id }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.tware && prItem.tware.name">
+            <div class=""
+              ><span class="name">调出单位:</span><span>{{ prItem.tware.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.tstore && prItem.tstore.name">
+            <div class=""
+              ><span class="name">调入单位:</span><span>{{ prItem?.store.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.tstore">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.tstore.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.tware">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.tware.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">收货单位:</span><span>{{ prItem.ware.name }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">收货单位:</span><span>{{ prItem.store.name }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item items mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">收货地址:</span><span>{{ prItem.store.address }}</span></div
+            >
+          </div>
+          <div class="item items mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">收货地址:</span><span>{{ prItem.ware.address }}</span></div
+            >
+          </div>
+        </div>
+        <div class="table">
+          <div class="tr">
+            <div class="item w10">序号</div>
+            <div class="item w20">编号</div>
+            <div class="item w30">商品</div>
+            <div class="item w20">数量</div>
+            <div class="item w20">单位</div>
+          </div>
+            <div class="tr" v-for="(item, index) in prItem.info" >
+              <div class="item w10">{{ index + 1 }}</div>
+              <div class="item w20">{{ item.bar_code }}</div>
+              <div class="item w30"
+                >{{ item.product_name }}</div
+              >
+              <div class="item w20">{{
+                item.is_weigh == 1 ? item.net_weight : item.product_num
+              }}</div>
+              <div class="item w20">{{ item.suk }}</div>
+            </div>
+        </div>
+        <div class="btm-tip">
+          <div class="itemt">
+            <span class="name">货品数:</span>
+            <span>{{ prItem.info.length }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">数量:</span>
+            <span>{{ getLen() }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">审核人:</span>
+            <span>{{ prItem.auth_admin_id ? prItem.auser.real_name : '' }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">仓管员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span class="name">财务员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span>打印时间:</span>
+            <span>{{ getTime() }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <template #footer>
+      <div style="flex: auto">
+        <BaseButton type="primary" @click="printing" v-print="printobj">打印</BaseButton>
+      </div>
+    </template>
+  </Dialog>
 </template>
+<style>
+@media print {
+  .section {
+    page-break-before: always;
+    margin-top: 0;
+  }
+}
+.bold {
+  font-weight: bold;
+}
+#dc {
+  font-size: 14px;
+  page-break-before: always;
+  padding: 10px;
+  position: relative;
+  padding-bottom: 100px;
+}
+.title {
+  font-size: 18px;
+  font-weight: bold;
+  color: #000000;
+}
+.top-tit {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+  padding: 20px 0 10px;
+}
+.item {
+  width: 50%;
+  /* margin-bottom: 10px; */
+}
+.mb10 {
+  margin-bottom: 10px;
+}
+.items {
+  width: 100% !important;
+}
+.name {
+  font-weight: bold;
+  color: #000000;
+}
+.table {
+  width: 98%;
+  text-align: center;
+  border-top: 1px solid #000;
+  /* border-left: 1px solid #000; */
+}
+.table > .tr {
+  display: flex;
+  flex-wrap: wrap;
+}
+.table .tr > .item {
+  padding: 5px 10px;
+  /* border-right: 1px solid #000; */
+  border-bottom: 1px solid #000;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.w30 {
+  width: 30%;
+}
+.w20 {
+  width: 20%;
+}
+.w10 {
+  width: 10%;
+}
+.table .th {
+  color: #000000;
+  padding: 10px 0;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+  min-width: 60px;
+}
+
+.table .td {
+  padding: 5px 3px;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+}
+@media print {
+  body,
+  html,
+  .previewPageBox {
+    height: auto !important;
+    overflow: visible !important;
+  }
+
+  .previewPageBox {
+    position: relative !important;
+  }
+}
+.btm-tip {
+  display: flex;
+  width: 100%;
+  flex-wrap: wrap;
+  padding-top: 150px;
+  
+}
+.btm-tip .itemt {
+  width: 33.3%;
+  margin-bottom: 10px;
+}
+</style>

+ 46 - 41
src/views/Erp/Out/OutEdit.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { onMounted, reactive, ref } from 'vue'
+import { onMounted, reactive, ref,computed } from 'vue'
 import { ContentWrap } from '@/components/ContentWrap'
 import {
   ElInput,
@@ -25,12 +25,7 @@ import { getProductDetail } from '@/api/goods'
 import { AttrBaseItem } from '@/api/goods/types'
 import { UpImgButtom } from '@/components/UpFile'
 import { outData, outGood } from '@/api/erp/types'
-import {
-  getStoreList,
-  getStoreUser,
-  getOutGood,
-  createOut
-} from '@/api/erp'
+import { getStoreList, getStoreUser, getOutGood, createOut } from '@/api/erp'
 const pageTitle = ref('添加')
 const { params } = useRoute()
 const { push } = useRouter()
@@ -233,7 +228,7 @@ const save = async (formEl: FormInstance | undefined) => {
           out_price: string
           price: string
         }) => {
-          if (!item['pur_number'] || item['pur_number'] < 0 ) {
+          if (!item['pur_number'] || item['pur_number'] < 0) {
             ok = false
             return ElMessage.error('请填写正确的出库商品数量')
           } else {
@@ -251,7 +246,6 @@ const save = async (formEl: FormInstance | undefined) => {
               out_price: item.out_price,
               price: item.price
             })
-            
           }
         }
       )
@@ -271,7 +265,7 @@ const save = async (formEl: FormInstance | undefined) => {
           out_price: string
           price: string
         }) => {
-          if (!item['pur_number'] || item['pur_number'] < 0 ) {
+          if (!item['pur_number'] || item['pur_number'] < 0) {
             ok = false
             return ElMessage.error('请填写正确的出库商品数量')
           } else {
@@ -289,14 +283,13 @@ const save = async (formEl: FormInstance | undefined) => {
               out_price: item.out_price,
               price: item.price
             })
-            
           }
         }
       )
     }
-    
-      console.log(ok, 'ok')
-    if (!ok) return;
+
+    console.log(ok, 'ok')
+    if (!ok) return
     // if()
     if (actinoTabIndex.value == 1) {
       if (selfBuild.type == 1 && selfBuild.up_wid == selfBuild.wid) {
@@ -305,8 +298,8 @@ const save = async (formEl: FormInstance | undefined) => {
       pData = {
         up_wid: selfBuild.up_wid,
         up_store_id: selfBuild.up_store_id,
-        wid: selfBuild.wid,
-        store_id: selfBuild.store_id,
+        wid: selfBuild.type == 1 ? selfBuild.wid: '',
+        store_id: selfBuild.type == 1? '': selfBuild.store_id,
         create_admin_id: selfBuild.create_admin_id || '',
         product_list: goods
       }
@@ -520,7 +513,6 @@ const getAdmin = async () => {
   }
 }
 
-
 const fristCheck = ref([])
 
 const changeSw = () => {
@@ -558,11 +550,9 @@ const confirmClick = () => {
     return item
   })
   if (actinoTabIndex.value == 1) {
-  checkGoods.value = unique(checkGoods.value.concat(fristCheck.value))
-    
-  } else if(actinoTabIndex.value == 2){
-  checkGoodss.value = unique(checkGoodss.value.concat(fristCheck.value))
-    
+    checkGoods.value = unique(checkGoods.value.concat(fristCheck.value))
+  } else if (actinoTabIndex.value == 2) {
+    checkGoodss.value = unique(checkGoodss.value.concat(fristCheck.value))
   }
 }
 
@@ -582,7 +572,8 @@ const getPurgood = async (page = 1, key = '') => {
     page: number
     limit: number
     up_store_id: any
-    type: any
+    type: any,
+    store_id?: any
   } = {
     up_wid: '',
     up_store_id: '',
@@ -593,23 +584,23 @@ const getPurgood = async (page = 1, key = '') => {
   }
   if (actinoTabIndex.value == 1) {
     if (selfBuild.type == 1 && !selfBuild.up_wid) {
-    return ElMessage.error('请选仓库')
-  }
-  if (selfBuild.type == 0 && !selfBuild.up_store_id) {
-    return ElMessage.error('请选门店')
+      return ElMessage.error('请选仓库')
     }
-    qData.up_wid = selfBuild.type === 1 ? selfBuild.up_wid : ''
-  qData.up_store_id = selfBuild.type === 0 ? selfBuild.up_store_id : ''
-  qData.type = selfBuild.type == 1 ? 0 : 1
-  }else if(actinoTabIndex.value == 2) {
+    // if (selfBuild.type == 0 && !selfBuild.up_store_id) {
+    //   return ElMessage.error('请选门店')
+    // }
+    // qData.up_wid = selfBuild.type === 1 ? selfBuild.up_wid : ''
+    qData.up_wid = selfBuild.up_wid
+    // qData.up_store_id = selfBuild.type === 0 ? selfBuild.up_store_id : ''
+    // qData.type = selfBuild.type == 1 ? 0 : 1
+    qData.type = 0
+  } else if (actinoTabIndex.value == 2) {
     if (!hzBuild.up_store_id) {
       return ElMessage.error('请选门店')
     }
     qData.up_store_id = hzBuild.up_store_id
     qData.type = 1
   }
- 
-
 
   const res = await getOutGood(qData)
   goods.value = res.data.data
@@ -632,6 +623,16 @@ const delCheckGoodss = (row) => {
 
 const up_wid = ref(0)
 const up_store_id = ref(0)
+const allPrice = computed(() => { 
+  return checkGoods.value.reduce((pre, cur:any) => {
+    return pre + cur.out_price * cur.pur_number
+  }, 0)
+})
+const allPrices = computed(() => { 
+  return checkGoodss.value.reduce((pre, cur:any) => {
+    return pre + cur.out_price * cur.pur_number
+  }, 0)
+})
 </script>
 <template>
   <ContentWrap
@@ -741,7 +742,7 @@ const up_store_id = ref(0)
             <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1, '')">
               选择商品
             </BaseButton>
-            <span class="pl20">价格合计()</span>
+            <span class="pl20">价格合计({{allPrice}})</span>
             <ElTable
               header-cell-class-name="bg-gray-100!"
               :data="checkGoods"
@@ -749,7 +750,7 @@ const up_store_id = ref(0)
               :border="true"
               stripe
             >
-            <ElTableColumn prop="product_id" label="ID"> </ElTableColumn>
+              <ElTableColumn prop="product_id" label="ID"> </ElTableColumn>
               <ElTableColumn prop="product_name" label="名称"> </ElTableColumn>
               <ElTableColumn prop="suk" label="单位"></ElTableColumn>
               <ElTableColumn prop="product_num" label="库存"></ElTableColumn>
@@ -785,7 +786,6 @@ const up_store_id = ref(0)
           :rules="rules"
           label-width="100px"
         >
-          
           <ElFormItem label="调出门店" prop="up_store_id">
             <ElSelect
               filterable
@@ -849,9 +849,10 @@ const up_store_id = ref(0)
             </ElSelect>
           </ElFormItem>
           <ElFormItem label="出库商品">
-            <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1,'')">
+            <BaseButton type="primary" style="margin-bottom: 20px" @click="getPurgood(1, '')">
               选择商品
             </BaseButton>
+            <span class="pl20">价格合计({{allPrices}})</span>
             <ElTable
               header-cell-class-name="bg-gray-100!"
               :data="checkGoodss"
@@ -859,8 +860,8 @@ const up_store_id = ref(0)
               :border="true"
               stripe
             >
-            <ElTableColumn prop="product_id" label="ID"> </ElTableColumn>
-            <ElTableColumn prop="product_name" label="名称"> </ElTableColumn>
+              <ElTableColumn prop="product_id" label="ID"> </ElTableColumn>
+              <ElTableColumn prop="product_name" label="名称"> </ElTableColumn>
               <ElTableColumn prop="suk" label="单位"></ElTableColumn>
               <ElTableColumn prop="product_num" label="库存"></ElTableColumn>
               <ElTableColumn prop="pur_number" label="出库数量">
@@ -940,7 +941,11 @@ const up_store_id = ref(0)
     class="text-center border-t-1px border-solid border-gray-200 py-10px mt-10px position-sticky bottom-0 left-0 right-0 bg-white"
   >
     <!-- <BaseButton v-if="params.type == 'edit'" @click="save(formRef)"> 保存 </BaseButton> -->
-    <BaseButton v-if="params.type == 'add' && actinoTabIndex == 1" @click="save(formRef)"> 保存</BaseButton>
-    <BaseButton v-if="params.type == 'add' && actinoTabIndex == 2" @click="save(formRefs)"> 保存</BaseButton>
+    <BaseButton v-if="params.type == 'add' && actinoTabIndex == 1" @click="save(formRef)">
+      保存</BaseButton
+    >
+    <BaseButton v-if="params.type == 'add' && actinoTabIndex == 2" @click="save(formRefs)">
+      保存</BaseButton
+    >
   </div>
 </template>

+ 354 - 94
src/views/Erp/Purchase/Purchase.vue

@@ -1,5 +1,6 @@
 <script setup lang="tsx">
-import { reactive, ref, unref } from 'vue'
+import { formatTime } from '@/utils'
+import { reactive, ref, unref,onMounted } from 'vue'
 import { useTable } from '@/hooks/web/useTable'
 import { useI18n } from '@/hooks/web/useI18n'
 import { Table, TableColumn } from '@/components/Table'
@@ -35,7 +36,8 @@ import {
   endPur,
   upCompute,
   authComput,
-  storeSimple
+  storeSimple,
+  getStoreList
 } from '@/api/erp'
 import { useRouter } from 'vue-router'
 //
@@ -52,10 +54,7 @@ const { tableRegister, tableState, tableMethods } = useTable({
       limit: unref(pageSize) || 10,
       ...unref(searchParams)
     })
-    return {
-      list: res.data.list,
-      total: res.data.count || 0
-    }
+    return { list: res.data.list, total: res.data.count || 0 }
   }
 })
 
@@ -63,12 +62,7 @@ const { dataList, loading, total, currentPage, pageSize } = tableState
 const { getList } = tableMethods
 
 const tableColumns = reactive<TableColumn[]>([
-  {
-    field: 'id',
-    label: 'ID',
-    align: 'center',
-    width: 70
-  },
+  { field: 'id', label: 'ID', align: 'center', width: 70 },
   // {
   //   field: 'logo',
   //   label: 'LOGO',
@@ -83,21 +77,9 @@ const tableColumns = reactive<TableColumn[]>([
   //     }
   //   }
   // },
-  {
-    field: 'purchase_order_id',
-    label: '采购单号',
-    minWidth: 230
-  },
-  {
-    field: 'want_order_id',
-    label: '要货单号',
-    minWidth: 230
-  },
-  {
-    field: 'order_price',
-    label: '订单金额',
-    minWidth: 150
-  },
+  { field: 'purchase_order_id', label: '采购单号', minWidth: 230 },
+  { field: 'want_order_id', label: '要货单号', minWidth: 230 },
+  { field: 'order_price', label: '订单金额', minWidth: 150 },
   {
     field: 'user',
     label: '采购方',
@@ -108,11 +90,7 @@ const tableColumns = reactive<TableColumn[]>([
       }
     }
   },
-  {
-    field: 'freight',
-    label: '运费',
-    width: 80
-  },
+  { field: 'freight', label: '运费', width: 80 },
   {
     field: 'info',
     label: '要货商品',
@@ -235,7 +213,7 @@ const tableColumns = reactive<TableColumn[]>([
                 删除
               </BaseButton>
               <ElDivider direction="vertical" />
-              <BaseButton link size="small" type="primary" onClick={() => action('auth', row)}>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
                 打印
               </BaseButton>
             </>
@@ -247,7 +225,7 @@ const tableColumns = reactive<TableColumn[]>([
                 完成
               </BaseButton>
               <ElDivider direction="vertical" />
-              <BaseButton link size="small" type="primary" onClick={() => action('auth', row)}>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
                 打印
               </BaseButton>
             </>
@@ -262,7 +240,7 @@ const tableColumns = reactive<TableColumn[]>([
                 拒绝收货
               </BaseButton>
               <ElDivider direction="vertical" />
-              <BaseButton link size="small" type="primary" onClick={() => action('auth', row)}>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
                 打印
               </BaseButton>
             </>
@@ -274,7 +252,7 @@ const tableColumns = reactive<TableColumn[]>([
                 提交结算
               </BaseButton>
               <ElDivider direction="vertical" />
-              <BaseButton link size="small" type="primary" onClick={() => action('auth', row)}>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
                 打印
               </BaseButton>
             </>
@@ -291,62 +269,115 @@ const tableColumns = reactive<TableColumn[]>([
                 审核结算
               </BaseButton>
               <ElDivider direction="vertical" />
-              <BaseButton link size="small" type="primary" onClick={() => action('auth', row)}>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
                 打印
               </BaseButton>
             </>
           )
         } else {
-          return <>
-              <BaseButton link size="small" type="primary" onClick={() => action('auth', row)}>
+          return (
+            <>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
                 打印
-              </BaseButton></>
+              </BaseButton>
+            </>
+          )
         }
       }
     }
   }
 ])
 
+const storeLoading = ref(false)
+const wareLoading = ref(false)
+const storeOptions = ref<any[]>([])
+const wareOptions = ref<any[]>([])
+  const getStore = async (query = '', id = '') => {
+  try {
+    storeLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, store: 1 })
+    if (res) {
+      storeOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    storeLoading.value = false
+  }
+}
+const getWare = async (query = '', id = '') => {
+  try {
+    wareLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, type: 3 })
+    if (res) {
+      wareOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    wareLoading.value = false
+  }
+}
+
 const searchSchema = reactive<FormSchema[]>([
+  // {
+  //   field: 'type',
+  //   label: '类型',
+  //   component: 'Select',
+  //   value: '',
+  //   componentProps: {
+  //     placeholder: '全部',
+  //     options: [
+  //       { label: '自营', value: '1' },
+  //       { label: '加盟', value: '2' },
+  //       { label: '仓库', value: '3' }
+  //     ]
+  //   }
+  // },
   {
-    field: 'type',
-    label: '类型',
+    field: 'purchase_order_id',
+    label: '采购单号',
+    component: 'Input',
+    value: '',
+    componentProps: { placeholder: '请输入采购单号' }
+  },
+  {
+    field: 'store_id',
+    label: '门店',
     component: 'Select',
     value: '',
     componentProps: {
-      placeholder: '全部',
-      options: [
-        {
-          label: '自营',
-          value: '1'
-        },
-        {
-          label: '加盟',
-          value: '2'
-        },
-        {
-          label: '仓库',
-          value: '3'
-        }
-      ]
+      placeholder: '请选择',
+      options: storeOptions
     }
   },
   {
-    field: 'name',
-    label: '名称',
-    component: 'Input',
+    field: 'wid',
+    label: '仓库',
+    component: 'Select',
     value: '',
     componentProps: {
-      placeholder: '请输入门店名称'
+      placeholder: '请选择',
+      options: wareOptions
     }
   }
 ])
 
-const searchParams = ref<{
-  type?: string
-}>({
-  type: ''
-})
+const searchParams = ref<{ type?: string }>({ type: '' })
 const setSearchParams = (data: any) => {
   searchParams.value = data
   getList()
@@ -372,9 +403,11 @@ const dialogVisibles = ref(false)
 const dialogVisibless = ref(false)
 const dialogVisiblesss = ref(false)
 const dialogVisiblessss = ref(false)
+const prDialogVisible = ref(false)
 const passdialog = ref(false)
 const outdialog = ref(false)
 
+const prItem = ref<any>({})
 const endItem = ref<endPuritem>({
   prove: '',
   purchasing_person_admin_id: 0,
@@ -461,9 +494,14 @@ const action = async (type: string, row?: any) => {
       cost: row.cost,
       roles: row.roles * 1
     }
+    dialogVisible.value = true
+
     console.log(currentRow, 'currentRow')
   }
-  dialogVisible.value = true
+  if (type === 'print') {
+    prItem.value = row
+    prDialogVisible.value = true
+  }
 }
 const delAction = (row: any) => {
   ElMessageBox.confirm('删除后无法恢复,是否删除?', {
@@ -474,11 +512,7 @@ const delAction = (row: any) => {
     .then(async () => {
       const re = await delPur(row.id)
       if (re) {
-        ElMessage({
-          showClose: true,
-          message: '删除成功',
-          type: 'success'
-        })
+        ElMessage({ showClose: true, message: '删除成功', type: 'success' })
       }
       await getList()
     })
@@ -506,10 +540,7 @@ const getAdmin = async () => {
   try {
     if (res) {
       adminOptions.value = res.data.map((item) => {
-        return {
-          value: item.id,
-          label: item.real_name
-        }
+        return { value: item.id, label: item.real_name }
       })
       console.log(adminOptions.value, 'adminOptions.value')
     } else {
@@ -531,11 +562,7 @@ const cancelClicks = () => {
   dialogVisibless.value = false
   authId.value = 0
   storeId.value = 0
-  endItem.value = {
-    id: 0,
-    purchasing_person_admin_id: 0,
-    info: []
-  }
+  endItem.value = { id: 0, purchasing_person_admin_id: 0, info: [] }
 }
 const confirmClick = async () => {
   if (!formData.value.auth_admin_id) {
@@ -586,11 +613,7 @@ const confirmClickss = async () => {
 }
 const cancelClickss = () => {
   dialogVisiblesss.value = false
-  endItem.value = {
-    id: 0,
-    purchasing_person_admin_id: 0,
-    info: []
-  }
+  endItem.value = { id: 0, purchasing_person_admin_id: 0, info: [] }
   compteData.value = { image: [], pay_time: '' }
 }
 const compteData = ref({ image: [], pay_time: '' })
@@ -606,11 +629,7 @@ const confirmClicksss = async () => {
 }
 const cancelClicksss = () => {
   dialogVisiblessss.value = false
-  endItem.value = {
-    id: 0,
-    purchasing_person_admin_id: 0,
-    info: []
-  }
+  endItem.value = { id: 0, purchasing_person_admin_id: 0, info: [] }
   authCompteData.value = { pay_status: 2 }
 }
 const passCancelClick = () => {
@@ -632,6 +651,42 @@ const passConfirmClick = async () => {
     formData.value.auth_admin_id = ''
   }
 }
+const printobj = ref({
+  id: 'dc',
+  popTitle: '好的打印标题',
+  extraCss:
+    'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css',
+  extraHead: '<meta http-equiv="content-language" content="zh-cn" />',
+  beforeOpenCallback(vue) {
+    vue.printLoading = true
+    console.log('打开之前')
+  },
+  openCallback(vue) {
+    vue.printLoading = false
+    console.log('执行了打印')
+  }
+})
+const getTime = () => {
+  let time = new Date().getTime()
+  return formatTime(time, 'yyyy-MM-dd HH:mm:ss')
+}
+const getLen = () => {
+  let sum = 0
+  prItem.value.info.forEach((item) => {
+    console.log(item.product_num)
+    if (item.is_weigh == 1) {
+      sum += item.net_weight * 1
+    } else {
+      sum += item.product_num * 1
+    }
+  })
+  return sum
+}
+
+onMounted(() => {
+  getStore()
+  getWare()
+})
 </script>
 
 <template>
@@ -650,9 +705,7 @@ const passConfirmClick = async () => {
       :data="dataList"
       :loading="loading"
       @register="tableRegister"
-      :pagination="{
-        total
-      }"
+      :pagination="{ total }"
     />
   </ContentWrap>
   <Dialog v-model="dialogVisibles" :title="dialogTitle" width="500px" maxHeight="160px">
@@ -871,4 +924,211 @@ const passConfirmClick = async () => {
       </div>
     </template>
   </Dialog>
+  <Dialog v-model="prDialogVisible" title="打印">
+    <div id="dc">
+      <div class="section">
+        <div class="text-center title">采购单</div>
+        <div class="top-tit">
+          <div class="item mb10">
+            <div class=""
+              ><span class="name">采购单号:</span><span>{{ prItem.purchase_order_id }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.ware && prItem.ware.name">
+            <div class=""
+              ><span class="name">采购单位:</span><span>{{ prItem.ware.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.store && prItem.store.name">
+            <div class=""
+              ><span class="name">采购单位:</span><span>{{ prItem?.store.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.store.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.ware.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item  mb10">
+            <div class=""
+              ><span class="name">供应商:</span><span>{{ prItem.supplier.name }}</span></div
+            >
+          </div>
+          <div class="item items mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">收货地址:</span><span>{{ prItem.store.address }}</span></div
+            >
+          </div>
+          <div class="item items mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">收货地址:</span><span>{{ prItem.ware.address }}</span></div
+            >
+          </div>
+        </div>
+        <div class="table">
+          <div class="tr">
+            <div class="item w10">序号</div>
+            <div class="item w20">编号</div>
+            <div class="item w30">商品</div>
+            <div class="item w20">数量</div>
+            <div class="item w20">单位</div>
+          </div>
+          <div class="tr" v-for="(item, index) in prItem.info">
+            <div class="item w10">{{ index + 1 }}</div>
+            <div class="item w20">{{ item.bar_code }}</div>
+            <div class="item w30">{{ item.product_name }}</div>
+            <div class="item w20">{{
+              item.is_weigh == 1 ? (item.net_weight || item.product_num) : item.product_num
+            }}</div>
+            <div class="item w20">{{ item.suk }}</div>
+          </div>
+        </div>
+        <div class="btm-tip">
+          <div class="itemt">
+            <span class="name">货品数:</span>
+            <span>{{ prItem.info.length }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">数量:</span>
+            <span>{{ getLen() }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">审核人:</span>
+            <span>{{ prItem.auth_admin_id ? prItem.auser.real_name : '' }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">仓管员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span class="name">财务员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span>打印时间:</span>
+            <span>{{ getTime() }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <template #footer>
+      <div style="flex: auto">
+        <BaseButton type="primary" v-print="printobj">打印</BaseButton>
+      </div>
+    </template>
+  </Dialog>
 </template>
+<style>
+@media print {
+  .section {
+    page-break-before: always;
+    margin-top: 0;
+  }
+}
+.bold {
+  font-weight: bold;
+}
+#dc {
+  font-size: 14px;
+  page-break-before: always;
+  padding: 10px;
+  position: relative;
+  padding-bottom: 100px;
+}
+.title {
+  font-size: 18px;
+  font-weight: bold;
+  color: #000000;
+}
+.top-tit {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+  padding: 20px 0 10px;
+}
+.item {
+  width: 50%;
+  /* margin-bottom: 10px; */
+}
+.mb10 {
+  margin-bottom: 10px;
+}
+.items {
+  width: 100% !important;
+}
+.name {
+  font-weight: bold;
+  color: #000000;
+}
+.table {
+  width: 98%;
+  text-align: center;
+  border-top: 1px solid #000;
+  /* border-left: 1px solid #000; */
+}
+.table > .tr {
+  display: flex;
+  flex-wrap: wrap;
+}
+.table .tr > .item {
+  padding: 5px 10px;
+  /* border-right: 1px solid #000; */
+  border-bottom: 1px solid #000;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.w30 {
+  width: 30%;
+}
+.w20 {
+  width: 20%;
+}
+.w10 {
+  width: 10%;
+}
+.table .th {
+  color: #000000;
+  padding: 10px 0;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+  min-width: 60px;
+}
+
+.table .td {
+  padding: 5px 3px;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+}
+@media print {
+  body,
+  html,
+  .previewPageBox {
+    height: auto !important;
+    overflow: visible !important;
+  }
+
+  .previewPageBox {
+    position: relative !important;
+  }
+}
+.btm-tip {
+  display: flex;
+  width: 100%;
+  flex-wrap: wrap;
+  padding-top: 150px;
+  
+}
+.btm-tip .itemt {
+  width: 33.3%;
+  margin-bottom: 10px;
+}
+</style>

+ 5 - 5
src/views/Erp/Role/Role.vue

@@ -112,12 +112,12 @@ const searchSchema = reactive<FormSchema[]>([
           value: ''
         },
         {
-          label: '不显示',
-          value: 0
+          label: '启用',
+          value: 1
         },
         {
-          label: '显示',
-          value: 1
+          label: '禁用',
+          value: 0
         }
       ]
     }
@@ -125,7 +125,7 @@ const searchSchema = reactive<FormSchema[]>([
 ])
 
 const searchParams = ref({
-  status: 1,
+  status: '',
   role_name: ''
 })
 const setSearchParams = (data: any) => {

+ 336 - 7
src/views/Erp/Simple/Simple.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { reactive, ref, unref } from 'vue'
+import { reactive, ref, unref, onMounted } from 'vue'
 import { useTable } from '@/hooks/web/useTable'
 import { useI18n } from '@/hooks/web/useI18n'
 import { Table, TableColumn } from '@/components/Table'
@@ -24,7 +24,8 @@ import {
   getSimple,
   storeSimple,
   wareSimple,
-  refuse
+  refuse,
+  getStoreList
 } from '@/api/erp'
 import { useRouter } from 'vue-router'
 import { formatTime } from '@/utils'
@@ -208,16 +209,66 @@ const tableColumns = reactive<TableColumn[]>([
               <BaseButton link size="small" type="danger" onClick={() => action('repass', row)}>
                 拒绝
               </BaseButton>
+              <ElDivider direction="vertical" />
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton>
             </>
           )
         } else {
-          return <></>
+          return <>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton></>
         }
       }
     }
   }
 ])
-
+const storeLoading = ref(false)
+const wareLoading = ref(false)
+const storeOptions = ref<any[]>([])
+const wareOptions = ref<any[]>([])
+  const getStore = async (query = '', id = '') => {
+  try {
+    storeLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, store: 1 })
+    if (res) {
+      storeOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    storeLoading.value = false
+  }
+}
+const getWare = async (query = '', id = '') => {
+  try {
+    wareLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, type: 3 })
+    if (res) {
+      wareOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    wareLoading.value = false
+  }
+}
 const searchSchema = reactive<FormSchema[]>([
   {
     field: 'type',
@@ -237,7 +288,27 @@ const searchSchema = reactive<FormSchema[]>([
         }
       ]
     }
-  }
+  },
+  {
+    field: 'store_id',
+    label: '门店',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: storeOptions
+    }
+  },
+  {
+    field: 'wid',
+    label: '仓库',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: wareOptions
+    }
+  },
   // {
   //   field: 'name',
   //   label: '名称',
@@ -279,9 +350,15 @@ const dialogVisibles = ref(false)
 const dialogVisibless = ref(false)
 const dialogVisiblesss = ref(false)
 const dialogVisiblessss = ref(false)
+const prDialogVisible = ref(false)
+const prItem = ref<any>({})
 
 const endItem = ref({ wid: '', store_id: '', id: '', info: [], out_order_id: ''})
 const action = async (type: string, row?: any) => {
+  if (type == 'print') {
+    prDialogVisible.value = true
+    prItem.value = row
+  }
   actionType.value = type
   if (type == 'repass') {
     endItem.value = row
@@ -466,8 +543,42 @@ const confirmClicks = async () => {
     cancelClicks()
   }
 }
+const getTime = () => {
+  let time = new Date().getTime()
+  return formatTime(time, 'yyyy-MM-dd HH:mm:ss')
+}
+const getLen = () => {
+  let sum = 0
+  prItem.value.info.forEach((item) => {
+    console.log(item.product_num)
+    if (item.is_weigh == 1) {
+      sum += item.net_weight * 1
+    } else {
+      sum += item.product_num * 1
+    }
+  })
+  return sum
+}
+const printobj = ref({
+  id: 'dc',
+  popTitle: '好的打印标题',
+  extraCss:
+    'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css',
+  extraHead: '<meta http-equiv="content-language" content="zh-cn" />',
+  beforeOpenCallback(vue) {
+    vue.printLoading = true
+    console.log('打开之前')
+  },
+  openCallback(vue) {
+    vue.printLoading = false
+    console.log('执行了打印')
+  }
+})
 
-
+onMounted(() => {
+  getStore()
+  getWare()
+})
 </script>
 
 <template>
@@ -554,5 +665,223 @@ const confirmClicks = async () => {
       </div>
     </template>
   </Dialog>
- 
+  <Dialog v-model="prDialogVisible" title="打印">
+    <div id="dc">
+      <div class="section">
+        <div class="text-center title">收货单</div>
+        <div class="top-tit">
+          <div class="item mb10">
+            <div class=""
+              ><span class="name">出库单号:</span><span>{{ prItem.out_order_id }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.ware && prItem.ware.name">
+            <div class=""
+              ><span class="name">收货单位:</span><span>{{ prItem.ware.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.store && prItem.store.name">
+            <div class=""
+              ><span class="name">收货单位:</span><span>{{ prItem?.store.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.store.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.ware.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <!-- <div class="item  mb10">
+            <div class=""
+              ><span class="name">供应商:</span><span>{{ prItem.supplier.name }}</span></div
+            >
+          </div> -->
+          <div class="item mb10" v-if="prItem?.tware">
+            <div class=""
+              ><span class="name">发货单位:</span><span>{{ prItem.tware.name }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.tstore">
+            <div class=""
+              ><span class="name">发货单位:</span><span>{{ prItem.tstore.name }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item items mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">收货地址:</span><span>{{ prItem.store.address }}</span></div
+            >
+          </div>
+          <div class="item items mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">收货地址:</span><span>{{ prItem.ware.address }}</span></div
+            >
+          </div>
+        </div>
+        <div class="table">
+          <div class="tr">
+            <div class="item w10">序号</div>
+            <div class="item w20">编号</div>
+            <div class="item w30">商品</div>
+            <div class="item w20">数量</div>
+            <div class="item w20">单位</div>
+          </div>
+          <div class="tr" v-for="(item, index) in prItem.info">
+            <div class="item w10">{{ index + 1 }}</div>
+            <div class="item w20">{{ item.bar_code }}</div>
+            <div class="item w30">{{ item.product_name }}</div>
+            <div class="item w20">{{
+              item.is_weigh == 1 ? item.net_weight : item.product_num
+            }}</div>
+            <div class="item w20">{{ item.suk }}</div>
+          </div>
+        </div>
+        <div class="btm-tip">
+          <div class="itemt">
+            <span class="name">货品数:</span>
+            <span>{{ prItem.info.length }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">数量:</span>
+            <span>{{ getLen() }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">审核人:</span>
+            <span>{{ prItem.auth_admin_id ? prItem.auser.real_name : '' }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">仓管员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span class="name">财务员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span>打印时间:</span>
+            <span>{{ getTime() }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <template #footer>
+      <div style="flex: auto">
+        <BaseButton type="primary" v-print="printobj">打印</BaseButton>
+      </div>
+    </template>
+  </Dialog>
 </template>
+<style>
+@media print {
+  .section {
+    page-break-before: always;
+    margin-top: 0;
+  }
+}
+.bold {
+  font-weight: bold;
+}
+#dc {
+  font-size: 14px;
+  page-break-before: always;
+  padding: 10px;
+  position: relative;
+  padding-bottom: 100px;
+}
+.title {
+  font-size: 18px;
+  font-weight: bold;
+  color: #000000;
+}
+.top-tit {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+  padding: 20px 0 10px;
+}
+.item {
+  width: 50%;
+  /* margin-bottom: 10px; */
+}
+.mb10 {
+  margin-bottom: 10px;
+}
+.items {
+  width: 100% !important;
+}
+.name {
+  font-weight: bold;
+  color: #000000;
+}
+.table {
+  width: 98%;
+  text-align: center;
+  border-top: 1px solid #000;
+  /* border-left: 1px solid #000; */
+}
+.table > .tr {
+  display: flex;
+  flex-wrap: wrap;
+}
+.table .tr > .item {
+  padding: 5px 10px;
+  /* border-right: 1px solid #000; */
+  border-bottom: 1px solid #000;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.w30 {
+  width: 30%;
+}
+.w20 {
+  width: 20%;
+}
+.w10 {
+  width: 10%;
+}
+.table .th {
+  color: #000000;
+  padding: 10px 0;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+  min-width: 60px;
+}
+
+.table .td {
+  padding: 5px 3px;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+}
+@media print {
+  body,
+  html,
+  .previewPageBox {
+    height: auto !important;
+    overflow: visible !important;
+  }
+
+  .previewPageBox {
+    position: relative !important;
+  }
+}
+.btm-tip {
+  display: flex;
+  width: 100%;
+  flex-wrap: wrap;
+  padding-top: 150px;
+  
+}
+.btm-tip .itemt {
+  width: 33.3%;
+  margin-bottom: 10px;
+}
+</style>

+ 319 - 4
src/views/Erp/Want/Want.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { reactive, ref, unref } from 'vue'
+import { reactive, ref, unref, onMounted } from 'vue'
 import { addCoupon, editCoupon } from '@/api/marketing'
 import { wantList } from '@/api/erp'
 import { useTable } from '@/hooks/web/useTable'
@@ -23,7 +23,7 @@ import {
 } from 'element-plus'
 import Write from './components/Write.vue'
 import { useRouter } from 'vue-router'
-import { getStoreUser,authWant, delWant } from '@/api/erp'
+import { getStoreUser,authWant, delWant,getStoreList } from '@/api/erp'
 import { formatTime } from '@/utils'
 import { FormSchema } from '@/components/Form'
 import { Search } from '@/components/Search'
@@ -199,11 +199,18 @@ const tableColumns = reactive<TableColumn[]>([
               <ElDivider direction="vertical" />
               <BaseButton link size="small" type="danger" onClick={() => delAction(row)}>
               删除
-            </BaseButton>
+              </BaseButton>
+              <ElDivider direction="vertical" />
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton>
             </>
           )
         } else {
-          return <></>
+          return <>
+              <BaseButton link size="small" type="primary" onClick={() => action('print', row)}>
+                打印
+              </BaseButton></>
         }
       }
     }
@@ -252,7 +259,13 @@ const getAdmin = async () => {
 // }
 const authId = ref(0)
 const storeId = ref(0)
+const prDialogVisible = ref(false)
+const prItem = ref<any>({})
 const action = async (type: string, row?: any) => {
+  if (type == 'print') {
+    prDialogVisible.value = true
+    prItem.value = row
+  }
   actionType.value = type
   if (type == 'add') {
     // dialogTitle.value = t('exampleDemo.add')
@@ -373,7 +386,79 @@ if(res.status == 200) {
   cancelClick()
 }
 }
+
+const storeLoading = ref(false)
+const wareLoading = ref(false)
+const storeOptions = ref<any[]>([])
+const wareOptions = ref<any[]>([])
+  const getStore = async (query = '', id = '') => {
+  try {
+    storeLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, store: 1 })
+    if (res) {
+      storeOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    storeLoading.value = false
+  }
+}
+const getWare = async (query = '', id = '') => {
+  try {
+    wareLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, type: 3 })
+    if (res) {
+      wareOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    wareLoading.value = false
+  }
+}
 const searchSchema = reactive<FormSchema[]>([
+  {
+    field: 'want_order_id',
+    label: '要货单号',
+    component: 'Input',
+    value: '',
+    componentProps: { placeholder: '请输入要货单号' }
+  },
+  {
+    field: 'store_id',
+    label: '门店',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: storeOptions
+    }
+  },
+  {
+    field: 'wid',
+    label: '仓库',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '请选择',
+      options: wareOptions
+    }
+  },
   {
     field: 'status',
     label: '状态',
@@ -420,6 +505,39 @@ const setSearchParams = (data: any) => {
   searchParams.value = data
   getList()
 }
+const getTime = () => {
+  let time = new Date().getTime()
+  return formatTime(time, 'yyyy-MM-dd HH:mm:ss')
+}
+const getLen = () => {
+  let sum = 0
+  prItem.value.info.forEach((item) => {
+    console.log(item.product_num)
+      sum += item.want_product_num * 1
+  })
+  return sum
+}
+const printobj = ref({
+  id: 'dc',
+  popTitle: '好的打印标题',
+  extraCss:
+    'https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css',
+  extraHead: '<meta http-equiv="content-language" content="zh-cn" />',
+  beforeOpenCallback(vue) {
+    vue.printLoading = true
+    console.log('打开之前')
+  },
+  openCallback(vue) {
+    vue.printLoading = false
+    console.log('执行了打印')
+  }
+})
+
+onMounted(() => {
+  getStore()
+  getWare()
+})
+
 </script>
 
 <template>
@@ -489,4 +607,201 @@ const setSearchParams = (data: any) => {
     </template>
   </Dialog>
   <!--  -->
+  <Dialog v-model="prDialogVisible" title="打印">
+    <div id="dc">
+      <div class="section">
+        <div class="text-center title">要货单</div>
+        <div class="top-tit">
+          <div class="item mb10">
+            <div class=""
+              ><span class="name">要货单号:</span><span>{{ prItem.want_order_id }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.mystore && prItem.mystore.name">
+            <div class=""
+              ><span class="name">要货单位:</span><span>{{ prItem?.mystore.name || '' }}</span></div
+            >
+          </div>
+          <div class="item mb10" v-if="prItem?.mystore">
+            <div class=""
+              ><span class="name">联系电话:</span><span>{{ prItem.mystore.phone }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.ware">
+            <div class=""
+              ><span class="name">出货单位:</span><span>{{ prItem.ware.name }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item mb10" v-if="prItem?.stroe">
+            <div class=""
+              ><span class="name">出货单位:</span><span>{{ prItem.stroe.name }}</span></div
+            >
+            <div class="val"></div>
+          </div>
+          <div class="item items mb10" v-if="prItem?.store">
+            <div class=""
+              ><span class="name">收货地址:</span><span>{{ prItem.store.address }}</span></div
+            >
+          </div>
+        </div>
+        <div class="table">
+          <div class="tr">
+            <div class="item w10">序号</div>
+            <div class="item w20">编号</div>
+            <div class="item w30">商品</div>
+            <div class="item w20">数量</div>
+            <div class="item w20">单位</div>
+          </div>
+          <div class="tr" v-for="(item, index) in prItem.info">
+            <div class="item w10">{{ index + 1 }}</div>
+            <div class="item w20">{{ item.bar_code }}</div>
+            <div class="item w30">{{ item.product_name }}</div>
+            <div class="item w20">{{
+              item.want_product_num}}</div>
+            <div class="item w20">{{ item.suk }}</div>
+          </div>
+        </div>
+        <div class="btm-tip">
+          <div class="itemt">
+            <span class="name">货品数:</span>
+            <span>{{ prItem.info.length }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">数量:</span>
+            <span>{{ getLen() }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">审核人:</span>
+            <span>{{ prItem.auth_admin_id ? prItem.auser.real_name : '' }}</span>
+          </div>
+          <div class="itemt">
+            <span class="name">仓管员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span class="name">财务员签字:</span>
+            <span></span>
+          </div>
+          <div class="itemt">
+            <span>打印时间:</span>
+            <span>{{ getTime() }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <template #footer>
+      <div style="flex: auto">
+        <BaseButton type="primary" v-print="printobj">打印</BaseButton>
+      </div>
+    </template>
+  </Dialog>
 </template>
+<style>
+@media print {
+  .section {
+    page-break-before: always;
+    margin-top: 0;
+  }
+}
+.bold {
+  font-weight: bold;
+}
+#dc {
+  font-size: 14px;
+  page-break-before: always;
+  padding: 10px;
+  position: relative;
+  padding-bottom: 100px;
+}
+.title {
+  font-size: 18px;
+  font-weight: bold;
+  color: #000000;
+}
+.top-tit {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+  padding: 20px 0 10px;
+}
+.item {
+  width: 50%;
+  /* margin-bottom: 10px; */
+}
+.mb10 {
+  margin-bottom: 10px;
+}
+.items {
+  width: 100% !important;
+}
+.name {
+  font-weight: bold;
+  color: #000000;
+}
+.table {
+  width: 98%;
+  text-align: center;
+  border-top: 1px solid #000;
+  /* border-left: 1px solid #000; */
+}
+.table > .tr {
+  display: flex;
+  flex-wrap: wrap;
+}
+.table .tr > .item {
+  padding: 5px 10px;
+  /* border-right: 1px solid #000; */
+  border-bottom: 1px solid #000;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.w30 {
+  width: 30%;
+}
+.w20 {
+  width: 20%;
+}
+.w10 {
+  width: 10%;
+}
+.table .th {
+  color: #000000;
+  padding: 10px 0;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+  min-width: 60px;
+}
+
+.table .td {
+  padding: 5px 3px;
+  border-left: 1px solid #000000;
+  border-top: 1px solid #000000;
+}
+@media print {
+  body,
+  html,
+  .previewPageBox {
+    height: auto !important;
+    overflow: visible !important;
+  }
+
+  .previewPageBox {
+    position: relative !important;
+  }
+}
+.btm-tip {
+  display: flex;
+  width: 100%;
+  flex-wrap: wrap;
+  padding-top: 150px;
+  
+}
+.btm-tip .itemt {
+  width: 33.3%;
+  margin-bottom: 10px;
+}
+</style>

+ 100 - 43
src/views/Goods/edit/add.vue

@@ -30,6 +30,7 @@ import { UpImgButtom } from '@/components/UpFile'
 import { getStoreList } from '@/api/store'
 import { isArray } from 'lodash-es'
 import { TableImage } from '@/components/tableImage'
+import { getUnitList } from '@/api/goods'
 const pageTitle = ref('添加')
 const { params } = useRoute()
 const { push } = useRouter()
@@ -37,7 +38,7 @@ const actinoTabIndex = ref(1)
 const productType = [
   { value: 0, label: '普通商品' },
   { value: 1, label: '卡密' },
-  { value: 2, label: '优券' },
+  { value: 2, label: '优券' },
   { value: 3, label: '虚拟商品' }
 ]
 const formData = reactive<goodsData & { attrs_value: attrsValue[]; keyword: string[] }>({
@@ -68,7 +69,7 @@ const formData = reactive<goodsData & { attrs_value: attrsValue[]; keyword: stri
   description: '',
   show_type: 0,
   is_verify: 0,
-  pay_qudou: 0,
+  pay_qudou: 1,
   is_vip_product: 0,
   is_weigh: 0,
   specs: [],
@@ -132,7 +133,7 @@ const getRulesForSpecType = (specType) => {
     return {
       sutimage: [validateField('image', '请选择商品图片')],
       stock: [validateField('stock', '请填写库存')],
-      price: [validateField('price', '请填写售价')],
+      price: [validateField('price', '请填写售价')]
       // cost: [validateField('cost', '请填写成本价')]
     }
   } else if (specType === 1) {
@@ -236,7 +237,10 @@ const flattenCateIds = (items: (number | number[])[]): Set<number> => {
  * @param {FormInstance | undefined} formEl - 表单实例,用于表单验证和获取表单数据
  * @returns {Promise<Array>} - 返回一个空数组,当前函数没有实际返回值,但为了保持接口一致性,返回了空数组
  */
+
+const loading = ref(false)
 const save = async (formEl: FormInstance | undefined) => {
+  if (loading.value == true) return
   // 检查表单实例是否存在,如果不存在则返回空数组
   if (!formEl) return []
 
@@ -254,10 +258,15 @@ const save = async (formEl: FormInstance | undefined) => {
   })
   // 验证商品规格
   let ggValid = false
+  let ggValids = false
+
   let arr: AttrBaseItem[] = []
   attrBase.forEach((item) => {
     let items = JSON.parse(JSON.stringify(item))
-    if (!item.bar_code || item.img.length != 1 || !item.name || !item.num || !item.rate) {
+    if (items.is_default) {
+      ggValids = true
+    }
+    if (item.img.length != 1 || !item.name || !item.num || !item.rate) {
       ggValid = true
     } else {
       items.img = item.img[0]
@@ -267,7 +276,9 @@ const save = async (formEl: FormInstance | undefined) => {
   if (ggValid) {
     return ElMessage.error('请正确填写规格参数')
   }
-
+  if (!ggValids) {
+    return ElMessage.error('请选择一个默认单位')
+  }
   // 如果表单数据有效,则准备数据并调用API进行保存
   if (valid) {
     // 将分类ID转换为数组形式,以便后续处理
@@ -305,7 +316,8 @@ const save = async (formEl: FormInstance | undefined) => {
       specs: arr
     }
     // 处理规格
-    console.log(data,'data')
+    console.log(data, 'data')
+    loading.value = true
     try {
       let res = {}
       // 根据操作类型(添加或编辑)调用相应的API
@@ -315,7 +327,6 @@ const save = async (formEl: FormInstance | undefined) => {
         data.id = formData.id
         res = await putProduct(data)
       }
-
       // 处理API调用结果,如果成功则显示成功消息并询问用户是否返回商品列表
       if (res) {
         let title = '添加'
@@ -326,21 +337,45 @@ const save = async (formEl: FormInstance | undefined) => {
         ElMessageBox.confirm(`${title}成功是否返回商品列表`, '提示', {
           confirmButtonText: '返回列表',
           cancelButtonText: `继续${title}`,
+          closeOnClickModal: false,
           type: 'warning'
-        }).then(() => {
-          backList()
         })
+          .then(() => {
+            backList()
+          })
+          .catch(() => {
+            loading.value = false
+            console.log('error')
+          })
       }
     } catch (error) {
       console.log(error)
+      loading.value = false
     } finally {
       // console.log(data)
     }
   }
 }
-
+interface op {
+  label: string
+  value: string
+  is_weigh: number
+}
+const unitList = ref<op[]>([])
+const getUnitLists = async () => {
+  const res = await getUnitList({
+    page: 1,
+    limit: 9999,
+    type: 'unit',
+    is_show: 1
+  })
+  unitList.value = res.data.list.map((item) => {
+    return { label: item.name, value: item.name, is_weigh: item.is_weigh }
+  })
+}
 const loadingData = ref(false)
 onMounted(async () => {
+  getUnitLists()
   //加载商品规格
   // ruleList()
   if (params.type == 'add') {
@@ -357,7 +392,7 @@ onMounted(async () => {
       formData.store_info = data.store_info
       formData.video_open = data.video_open
       formData.video_link = data.video_link
-      formData.slider_image = data.slider_image ? data.slider_image.split(','):[]
+      formData.slider_image = data.slider_image ? data.slider_image.split(',') : []
       formData.image = [data.image]
       // formData.bar_code = data.bar_code
       formData.recommend_image = data.recommend_image
@@ -381,11 +416,13 @@ onMounted(async () => {
       formData.is_verify = data.is_verify
       formData.cost = data.cost
       // formData.specs = data.specs
-      attrBase = reactive(data.specs.map(item => {
-        let obj = JSON.parse(JSON.stringify(item))
-        obj.img = [item.img]
-        return obj
-      }))
+      attrBase = reactive(
+        data.specs.map((item) => {
+          let obj = JSON.parse(JSON.stringify(item))
+          obj.img = [item.img]
+          return obj
+        })
+      )
       //加载门店
       getStore('', data.store_id)
       console.log('z')
@@ -402,7 +439,7 @@ const storeOptions = ref<any[]>([])
 const getStore = async (query = '', id = '') => {
   try {
     storeLoading.value = true
-    const res = await getStoreList({ page: 1, limit: 100, name: query, id ,store: 1})
+    const res = await getStoreList({ page: 1, limit: 100, name: query, id, store: 1 })
     if (res) {
       storeOptions.value = res.data.list.map((item) => {
         return {
@@ -443,22 +480,22 @@ const addAttr = () => {
   console.log('zhe')
   try {
     attrBase.push({
-    img: [], //图片
-    bar_code: '', //产品编号
-    price: 0, //售价
-    num: 0,
-    is_default: 0,
-    price_1: 0,
-    price_2: 0,
-    price_3: 0,
-    name: '',
-    is_del: 0,
-    rate: 0
-  })
+      img: [], //图片
+      bar_code: '', //产品编号
+      price: 0, //售价
+      num: 0,
+      is_default: 0,
+      price_1: 0,
+      price_2: 0,
+      price_3: 0,
+      name: '',
+      is_del: 0,
+      rate: 0
+    })
   } catch (error) {
-    console.log('添加错误:',error)
+    console.log('添加错误:', error)
   }
-  
+
   // actionAttrs.push({
   //   attrHidden: '',
   //   detail: [attrItem.value],
@@ -542,6 +579,13 @@ const delAttr = (index) => {
     addAttr()
   }
 }
+const chooseUnit = (e) => {
+  console.log(e)
+  let unit = unitList.value.find((item) => item.value == e)
+  if (unit) {
+    formData.is_weigh = unit.is_weigh
+  }
+}
 </script>
 <template>
   <ContentWrap
@@ -614,12 +658,7 @@ const delAttr = (index) => {
           <!-- <ElFormItem label="条码" prop="keyword">
             <ElInput v-model="formData.bar_code"  placeholder="请输入条码" />
           </ElFormItem> -->
-          <ElFormItem label="是否称重" prop="is_weigh">
-            <ElRadioGroup v-model="formData.is_weigh">
-              <ElRadio :value="0">否</ElRadio>
-              <ElRadio :value="1">是</ElRadio>
-            </ElRadioGroup>
-          </ElFormItem>
+
           <ElFormItem label="商品简介" prop="store_info">
             <ElInput
               type="textarea"
@@ -650,10 +689,10 @@ const delAttr = (index) => {
             <ElInput type="number" v-model="formData.cost" placeholder="请输入成本价" />
           </ElFormItem>
         </ElTabPane>
-        <ElTabPane label="商品规格" :name="2">
+        <ElTabPane label="商品单位" :name="2">
           <ElFormItem label="商品属性">
             <BaseButton type="primary" style="margin-bottom: 20px" @click="addAttr">
-              新增规格
+              新增单位
             </BaseButton>
             <ElTable
               header-cell-class-name="bg-gray-100!"
@@ -672,14 +711,26 @@ const delAttr = (index) => {
                   />
                 </template>
               </ElTableColumn>
-              <ElTableColumn prop="name" label="规格名称">
-                <template #header> <span>规格名称</span><span class="text-red">*</span> </template>
+              <ElTableColumn prop="name" label="单位">
+                <template #header> <span>单位</span><span class="text-red">*</span> </template>
                 <template #default="{ row }">
-                  <ElInput type="text" v-model="row.name" />
+                  <!-- <ElInput type="text" v-model="row.name" /> -->
+                  <ElSelect
+                    v-model="row.name"
+                    class="m-2"
+                    placeholder="请选择单位"
+                    @change="chooseUnit"
+                  >
+                    <ElOption
+                      v-for="item in unitList"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value"
+                    />
+                  </ElSelect>
                 </template>
               </ElTableColumn>
               <ElTableColumn prop="bar_code" label="条码">
-                <template #header> <span>条码</span><span class="text-red">*</span> </template>
                 <template #default="{ row }">
                   <ElInput type="text" v-model="row.bar_code" />
                 </template>
@@ -753,6 +804,12 @@ const delAttr = (index) => {
           </ElFormItem>
         </ElTabPane>
         <ElTabPane label="其他设置" :name="5">
+          <ElFormItem label="是否称重" prop="is_weigh">
+            <ElRadioGroup v-model="formData.is_weigh">
+              <ElRadio :value="0">否</ElRadio>
+              <ElRadio :value="1">是</ElRadio>
+            </ElRadioGroup>
+          </ElFormItem>
           <ElFormItem label="虚拟销量" prop="ficti">
             <ElInput type="number" v-model="formData.ficti" placeholder="请输入虚拟销量" />
           </ElFormItem>

+ 39 - 17
src/views/Goods/list/index.vue

@@ -25,9 +25,9 @@ import {
   ElTableColumn,
   ElPagination,
   ElMessage,
+  ElText,
   ElTabs,
-  ElTabPane,
-  ElText
+  ElTabPane
 } from 'element-plus'
 import type { Action } from 'element-plus'
 import { TableImage } from '@/components/tableImage'
@@ -73,6 +73,7 @@ const dataList = ref<any[]>([])
 const loading = ref(false)
 
 onMounted(async () => {
+  getStoreLists()
   try {
     getTabNumber('examine') //待审核商品数量
     getTabNumber('dom') //仓鼠中商品数量
@@ -146,9 +147,19 @@ const getTabNumber = async (name) => {
     // 确保无论成功与否,都会将加载状态设置为 false
   }
 }
+const storeOpt = ref([])
+const getStoreLists = async () => {
+  const res = await getStoreList({ page: 1, limit: 100, store: 1 })
+ storeOpt.value = res.data.list.map((item) => {
+    return {
+      value: item.id,
+      label: item.name
+    }
+  })
+}
 const searchSchema = reactive<FormSchema[]>([
   {
-    field: 'name',
+    field: 'store_name',
     label: '商品名称',
     component: 'Input',
     componentProps: {
@@ -160,17 +171,18 @@ const searchSchema = reactive<FormSchema[]>([
     label: '门店',
     component: 'Select',
     componentProps: {
-      placeholder: '请选择要搜索的门店'
+      placeholder: '请选择要搜索的门店',
+      options: storeOpt
     },
-    optionApi: async () => {
-      const { data } = await getStoreList({ page: 1, limit: 100 })
-      return data.list.map((item) => {
-        return {
-          value: item.id,
-          label: item.name
-        }
-      })
-    }
+    // optionApi: async () => {
+    //   const { data } = await getStoreList({ page: 1, limit: 100 })
+    //   return data.list.map((item) => {
+    //     return {
+    //       value: item.id,
+    //       label: item.name
+    //     }
+    //   })
+    // }
   },
   {
     field: 'is_verify',
@@ -420,6 +432,12 @@ const audit = async (id, is_verify, refusal) => {
     console.log(error)
   }
 }
+const showStore = (id:number) => {
+  let store : { label: string ,value: number} = storeOpt.value.find((item: any) => item.value == id) || {label: '',value: 0}
+  if (store) {
+    return store.label
+  }
+}
 </script>
 
 <template>
@@ -430,7 +448,7 @@ const audit = async (id, is_verify, refusal) => {
         :key="index"
         :label="`${item.title}${item.total > 0 ? `(${item.total})` : ''}`"
         :name="index"
-        >{{ index }}
+        >
       </ElTabPane>
     </ElTabs> -->
     <div class="max-w-1000px">
@@ -444,7 +462,7 @@ const audit = async (id, is_verify, refusal) => {
     </div>
     <div class="mb-10px">
       <BaseButton type="primary" @click="action('add')">{{ t('exampleDemo.add') }}</BaseButton>
-      <BaseButton @click="allSet" :disabled="selectList.length == 0">批量设置</BaseButton>
+      <!-- <BaseButton @click="allSet" :disabled="selectList.length == 0">批量设置</BaseButton> -->
     </div>
     <ElTable @selection-change="selectChange" v-loading="loading" node-key="id" :data="dataList">
       <ElTableColumn type="selection" prop="selection" />
@@ -454,8 +472,12 @@ const audit = async (id, is_verify, refusal) => {
           <TableImage :src="row.image" alt="商品图片" />
         </template>
       </ElTableColumn>
-      <ElTableColumn prop="name" label="商品名称" minWidth="180" />
-      <ElTableColumn prop="store_name" label="门店" minWidth="150" />
+      <ElTableColumn prop="store_name" label="商品名称" minWidth="180" />
+      <ElTableColumn prop="store_id" label="门店" minWidth="180">
+        <template #default="{ row }">
+          <div>{{showStore(row.store_id)}}</div>
+        </template>
+      </ElTableColumn>
       <ElTableColumn prop="price" label="商品售价" minWidth="80" />
       <ElTableColumn prop="stock" label="库存" minWidth="80" />
       <ElTableColumn prop="sales" label="销量" minWidth="80" />

+ 127 - 0
src/views/Goods/unit/components/Write.vue

@@ -0,0 +1,127 @@
+<script setup lang="tsx">
+import { watch, ref } from 'vue'
+import { productUnit } from '@/api/goods/types'
+import { getProductUnitDetail, addProductUnit, putProductUnit } from '@/api/goods'
+import { ElForm, ElFormItem, ElInput, ElMessage, ElRadioGroup, ElRadio } from 'element-plus'
+import type { FormInstance } from 'element-plus'
+import { Dialog } from '@/components/Dialog'
+import { useI18n } from '@/hooks/web/useI18n'
+const { t } = useI18n()
+
+const props = defineProps({
+  id: {
+    type: Number,
+    default: 0
+  },
+  title: {
+    type: String,
+    default: ''
+  }
+})
+const modelValue = defineModel<boolean>()
+const ruleFormRef = ref<FormInstance>()
+const emit = defineEmits(['submit'])
+const submit = async () => {
+  if (ruleFormRef.value) {
+    const valid = await ruleFormRef.value.validate((valid, fields) => {
+      // console.log(fields, 'fields')
+      if (!valid) {
+        console.log('error submit!', fields)
+      }
+    })
+    if (valid) {
+      loadingData.value = true
+      try {
+        let re: any = {}
+        if (form.value.id > 0) {
+          re = await putProductUnit(form.value)
+        } else if (form.value.id == 0) {
+          re = await addProductUnit(form.value)
+        }
+        if (re.status == 200) {
+          ElMessage({
+            showClose: true,
+            message: '添加成功',
+            type: 'success'
+          })
+        }
+        form.value = {
+          name: '',
+          id: 0,
+          type: 'unit',
+          pid: 0,
+          sort: 0,
+          is_show: 1,
+          path: '',
+          is_weigh: 0
+        }
+        emit('submit')
+      } catch (error) {
+        console.log(error)
+      } finally {
+        loadingData.value = false
+      }
+    }
+  }
+}
+const loadingData = ref(false)
+watch(
+  () => props.id,
+  async (value) => {
+    if (value * 1 === 0) return
+    loadingData.value = true
+    const res = await getProductUnitDetail(value)
+    form.value = res.data
+    loadingData.value = false
+  },
+  {
+    deep: true,
+    immediate: true
+  }
+)
+const form = ref<productUnit>({
+  name: '',
+  id: 0,
+  type: 'unit',
+  pid: 0,
+  sort: 0,
+  is_show: 1,
+  path: '',
+  is_weigh: 0
+})
+</script>
+
+<template>
+  <Dialog v-model="modelValue" :title="title" width="600px">
+    <el-form v-loading="loadingData" ref="ruleFormRef" :model="form" label-width="auto">
+      <el-form-item
+        prop="name"
+        label="单位名称"
+        :rules="[{ required: true, message: '单位名称', trigger: 'blur' }]"
+      >
+        <el-input v-model="form.name" />
+      </el-form-item>
+      <el-form-item prop="sort" label="排序">
+        <el-input v-model="form.sort" />
+      </el-form-item>
+      <el-form-item prop="is_weigh" label="是否称重">
+        <el-radio-group v-model="form.is_weigh" class="ml-4">
+          <el-radio :label="1" size="large">是</el-radio>
+          <el-radio :label="0" size="large">否</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item prop="is_show" label="是否显示">
+        <el-radio-group v-model="form.is_show" class="ml-4">
+          <el-radio :label="1" size="large">是</el-radio>
+          <el-radio :label="0" size="large">否</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <BaseButton type="primary" :loading="loadingData" @click="submit">
+        {{ t('exampleDemo.save') }}
+      </BaseButton>
+      <BaseButton @click="modelValue = false">{{ t('dialogDemo.close') }}</BaseButton>
+    </template>
+  </Dialog>
+</template>

+ 268 - 0
src/views/Goods/unit/index.vue

@@ -0,0 +1,268 @@
+<script setup lang="tsx">
+import { reactive, ref, unref } from 'vue'
+import { useTable } from '@/hooks/web/useTable'
+import { useI18n } from '@/hooks/web/useI18n'
+import { Table, TableColumn } from '@/components/Table'
+import { ContentWrap } from '@/components/ContentWrap'
+import { BaseButton } from '@/components/Button'
+import { ElDivider, ElMessage, ElMessageBox,ElTag } from 'element-plus'
+import Write from './components/Write.vue'
+import { delProductUnit,getUnitList } from '@/api/goods'
+import { FormSchema } from '@/components/Form'
+import { Search } from '@/components/Search'
+
+const { t } = useI18n()
+
+const { tableRegister, tableState, tableMethods } = useTable({
+  fetchDataApi: async () => {
+    const res = await getUnitList({
+      ...searchParams.value,
+      page: unref(currentPage) || 1,
+      limit: unref(pageSize) || 10,
+    })
+    return {
+      list: res.data.list,
+      total: res.data.count || 0
+    }
+  }
+})
+
+const { dataList, loading, total, currentPage, pageSize } = tableState
+const { getList } = tableMethods
+
+const tableColumns = reactive<TableColumn[]>([
+  {
+    field: 'id',
+    label: 'ID',
+    width: 100
+  },
+  {
+    field: 'name',
+    label: '单位名称',
+    minWidth: 100
+  },
+  {
+    field: 'is_weigh',
+    label: '是否称重',
+    width: 200,
+    align: 'center',
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        if (row.is_weigh == 1) {
+          return (
+            <>
+          <ElTag >是</ElTag></>
+          )
+        } else {
+          return (
+          <>
+            <ElTag type="info">否</ElTag></>
+        )
+        }
+        
+      }
+    }
+  },
+  {
+    field: 'is_show',
+    label: '是否显示',
+    width: 200,
+    align: 'center',
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        if (row.is_show == 1) {
+          return (
+            <>
+          <ElTag >是</ElTag></>
+          )
+        } else {
+          return (
+          <>
+            <ElTag type="info">否</ElTag></>
+        )
+        }
+      }
+    }
+  },
+  {
+    field: 'action',
+    label: t('userDemo.action'),
+    width: 200,
+    fixed: 'right',
+    align: 'center',
+    headerAlign: 'center',
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        return (
+          <>
+            <BaseButton link size="small" type="primary" onClick={() => action('edit', row)}>
+              编辑
+            </BaseButton>
+            <ElDivider direction="vertical" />
+            <BaseButton link size="small" type="danger" onClick={() => delAction(row)}>
+              删除
+            </BaseButton>
+          </>
+        )
+      }
+    }
+  }
+])
+
+const dialogVisible = ref(false)
+const currentRow = ref(0)
+const dialogTitle = ref('')
+const actionType = ref('')
+
+const action = async (type: string, row?: any) => {
+  actionType.value = type
+
+  if (type == 'add') {
+    dialogTitle.value = t('exampleDemo.add')
+    currentRow.value = 0
+  }
+  if (type == 'edit') {
+    dialogTitle.value = t('exampleDemo.edit')
+    currentRow.value = row.id
+  }
+  
+  dialogVisible.value = true
+}
+const delAction = (row: any) => {
+  ElMessageBox.confirm('删除后无法恢复,是否删除?', {
+    confirmButtonText: '删除',
+    cancelButtonText: '取消',
+    type: 'warning'
+  })
+    .then(async () => {
+      const re = await delProductUnit(row.id)
+      if (re) {
+        ElMessage({
+          showClose: true,
+          message: '删除成功',
+          type: 'success'
+        })
+      }
+      await getList()
+    })
+    .catch(() => {})
+}
+const save = async () => {
+  getList()
+  dialogVisible.value = false
+}
+const searchSchema = reactive<FormSchema[]>([
+  {
+    field: 'name',
+    label: '单位名称',
+    component: 'Input',
+    componentProps: {
+      placeholder: '请输入单位名称'
+    }
+  },
+  {
+    field: 'type',
+    label: '类型',
+    value: 'unit',
+    hidden: true,
+    componentProps: {
+      placeholder: ''
+    }
+  },
+  {
+    field: 'pid',
+    label: '类型',
+    value: 0,
+    hidden: true,
+    componentProps: {
+      placeholder: ''
+    }
+  },
+  {
+    field: 'is_show',
+    label: '是否显示',
+    component: 'Select',
+    value: -1,
+    componentProps: {
+      placeholder: '全部',
+      options: [
+        {
+          label: '全部',
+          value: -1
+        },
+        {
+          label: '显示',
+          value: 1
+        },
+        {
+          label: '隐藏',
+          value: 0
+        }
+      ]
+    }
+  },
+  {
+    field: 'is_weigh',
+    label: '是否称重',
+    component: 'Select',
+    value: -1,
+    componentProps: {
+      placeholder: '全部',
+      options: [
+        {
+          label: '全部',
+          value: -1
+        },
+        {
+          label: '是',
+          value: 1
+        },
+        {
+          label: '否',
+          value: 0
+        }
+      ]
+    }
+  }
+])
+const searchParams = ref<{ type: string,name: string,pid:number }>({ type: 'unit',name: '',pid: 0 })
+
+const setSearchParams = (data: any) => {
+  searchParams.value = data
+  getList()
+}
+</script>
+
+<template>
+  <ContentWrap>
+    <Search :schema="searchSchema" @reset="setSearchParams" @search="setSearchParams" />
+
+    <div class="mb-10px">
+      <BaseButton type="primary" @click="action('add')">{{ t('exampleDemo.add') }}</BaseButton>
+    </div>
+    <Table
+      v-model:current-page="currentPage"
+      v-model:page-size="pageSize"
+      :columns="tableColumns"
+      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+      stripe
+      :data="dataList"
+      :loading="loading"
+      @register="tableRegister"
+      :pagination="{
+        total
+      }"
+    />
+  </ContentWrap>
+
+  <Write
+    v-model="dialogVisible"
+    :title="dialogTitle"
+    ref="writeRef"
+    :id="currentRow"
+    @submit="save"
+  />
+</template>

+ 25 - 2
src/views/Marketing/Rechange/Rechange.vue

@@ -104,16 +104,39 @@ const tableColumns = reactive<TableColumn[]>([
 ])
 
 const searchSchema = reactive<FormSchema[]>([
+  {
+    field: 'type',
+    label: '类型',
+    component: 'Select',
+    value: '',
+    componentProps: {
+      placeholder: '全部',
+      options: [
+        {
+          label: '全部',
+          value: ''
+        },
+        {
+          label: '全局',
+          value: 0
+        },
+        {
+          label: '门店',
+          value: 1
+        }
+      ]
+    }
+  },
   {
     field: 'store_id',
     label: '门店',
     component: 'Select',
     value: '',
     componentProps: {
-      placeholder: '请选择',
+      placeholder: '请选择门店',
       options: storeList
     }
-  },
+  }
 ])
 
 const searchParams = ref<{

+ 58 - 6
src/views/Marketing/coupon/components/Write.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import {  ref, reactive } from 'vue'
+import { ref, reactive, onMounted } from 'vue'
 import {
   ElForm,
   ElFormItem,
@@ -8,9 +8,11 @@ import {
   ElInput,
   ElCascader,
   FormInstance,
-  ElMessage
+  ElMessage,
+  ElSelect,
+  ElOption
 } from 'element-plus'
-import { getProductCategory } from '@/api/goods'
+import { getProductCategory, getProduct } from '@/api/goods'
 
 const coupon = ref({
   type: 0,
@@ -20,13 +22,15 @@ const coupon = ref({
   coupon_time: 0,
   sort: 0,
   status: 1,
-  category_id: ''
+  category_id: '',
+  product_id: []
 })
 
 const rules = reactive({
   title: [{ required: true, message: '请输入优惠券名称', trigger: 'blur' }],
   coupon_price: [{ required: true, message: '请输入优惠券面值', trigger: 'blur' }],
-  category_id: [{ required: true, message: '请输入优惠券面值', trigger: 'change' }]
+  category_id: [{ required: true, message: '请选择商品分类', trigger: 'change' }],
+  product_id: [{ required: true, message: '请选择商品', trigger: 'change' }]
 })
 const cateIdsProps = {
   checkStrictly: false,
@@ -58,7 +62,7 @@ const emits = defineEmits(['addCoupon'])
 //   submit
 // })
 const save = async (elRef) => {
-   await elRef.validate((valid, fields) => {
+  await elRef.validate((valid, fields) => {
     if (valid) {
       console.log('submit!', valid)
       emits('addCoupon', coupon.value)
@@ -70,6 +74,35 @@ const save = async (elRef) => {
     }
   })
 }
+
+interface opt {
+  label: string
+  value: string
+}
+const goodOptions = ref<opt[]>([])
+const loading = ref(false)
+const remoteMethod = (query: string) => {
+  if (query) {
+    loading.value = true
+    getProduct({
+      page: 1,
+      limit: 1000,
+      store_name: query
+    }).then((res) => {
+      loading.value = false
+      goodOptions.value = res.data.list.map((item) => {
+        return {
+          label: '( ' + item.id + ')' + item.store_name,
+          value: item.id
+        }
+      })
+    }).catch(() => {
+      loading.value = false
+    })
+  } else {
+    goodOptions.value = []
+  }
+}
 </script>
 
 <template>
@@ -94,6 +127,25 @@ const save = async (elRef) => {
     <ElFormItem label="优惠券名称" prop="title">
       <ElInput v-model="coupon.title" placeholder="请输入优惠券名称" />
     </ElFormItem>
+    <ElFormItem label="商品" prop="product_id" v-if="coupon.type == 2">
+      <ElSelect
+        v-model="coupon.product_id"
+        multiple
+        filterable
+        remote
+        reserve-keyword
+        :remote-method="remoteMethod"
+        :loading="loading"
+        placeholder="请选择商品"
+      >
+        <ElOption
+          v-for="item in goodOptions"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+        />
+      </ElSelect>
+    </ElFormItem>
     <ElFormItem label="优惠券面值" prop="coupon_price">
       <ElInput type="number" v-model="coupon.coupon_price" placeholder="请输入优惠券面值" />
     </ElFormItem>

+ 2 - 1
src/views/Marketing/coupon/index.vue

@@ -176,7 +176,8 @@ const save = async (coupon) => {
     coupon_time: coupon.coupon_time,
     sort: coupon.sort,
     status: coupon.status,
-    category_id: coupon.category_id || ''
+    category_id: coupon.category_id || '',
+    product_id: coupon.product_id || [],
   }
   try {
     if (actionType.value === 'edit') {

+ 16 - 3
src/views/Marketing/coupon/list.vue

@@ -1,6 +1,6 @@
 <script setup lang="tsx">
 import { reactive, ref, unref } from 'vue'
-import {addCoupon, editCoupon, releaseCoupon,couponList,couponDel } from '@/api/marketing'
+import {addCoupon, editCoupon, releaseCoupon,couponList,couponDel,changeCouponField } from '@/api/marketing'
 import { useTable } from '@/hooks/web/useTable'
 import { useI18n } from '@/hooks/web/useI18n'
 import { Table, TableColumn } from '@/components/Table'
@@ -54,7 +54,7 @@ const tableColumns = reactive<TableColumn[]>([
   },
   {
     field: 'time',
-    label: '面值',
+    label: '生效时间',
     minWidth: 100,
     slots: {
       default: ({ row }: any) => {
@@ -140,7 +140,7 @@ const tableColumns = reactive<TableColumn[]>([
     slots: {
       default: (data: any) => {
         const row = data.row
-        if (data.status == 0) {
+        if (row.status == 0) {
           return (
           <>
             <BaseButton link size="small" type="primary" onClick={() => action('list', row)}>
@@ -195,6 +195,16 @@ const dialogTitle = ref('')
 const actionType = ref('')
 const saveLoading = ref(false)
 
+const changeCouponFields = (row) => {
+  changeCouponField({
+    id: row.id,
+    field: 'status',
+    status: row.status === 1 ? 0 : 1
+  }).then(() => {
+    getList()
+  })
+}
+
 // function arrayToObject(array) {
 //     var obj = {};
 //     for (var i = 0; i < array.length; i++) {
@@ -214,6 +224,9 @@ const action = async (type: string, row?: any) => {
     cid.value = row.id*1
     dialogVisibles.value = true
   }
+  if (type == 'open' || type == 'close') {
+    changeCouponFields(row)
+  }
 }
 const delAction = (row: any) => {
   ElMessageBox.confirm('删除后无法恢复,是否删除?', {

+ 293 - 98
src/views/Order/orderList/index.vue

@@ -1,5 +1,5 @@
 <script setup lang="tsx">
-import { reactive, ref, unref } from 'vue'
+import { reactive, ref, unref,onMounted } from 'vue'
 // import { getOrderList, assignSalesman, getOrderDetail } from '@/api/order'
 import { getOrderList, getOrderDetail } from '@/api/order'
 import { useTable } from '@/hooks/web/useTable'
@@ -7,14 +7,15 @@ import { Table, TableColumn } from '@/components/Table'
 import { ContentWrap } from '@/components/ContentWrap'
 import { FormSchema } from '@/components/Form'
 import { Search } from '@/components/Search'
-import { Dialog } from '@/components/Dialog'
 import { searchTime } from '@/utils/searchTime'
 import { searchOrder } from '@/api/order/types'
-import { ElTabs, ElTabPane, ElButton, ElDivider, ElDrawer } from 'element-plus'
+import { ElTabs, ElTabPane, ElButton, ElDrawer } from 'element-plus'
 import Detail from './components/Detail.vue'
 import Draft from './components/Draft.vue'
 import addItem from './components/addItem.vue'
-import { SalespersonButtom } from '@/components/SalespersonList'
+import {
+  getStoreList
+} from '@/api/erp'
 const { tableRegister, tableState, tableMethods } = useTable({
   fetchDataApi: async () => {
     const res = await getOrderList({
@@ -33,8 +34,6 @@ const { dataList, loading, total, currentPage, pageSize } = tableState
 const { getList } = tableMethods
 const dialogVisible = ref(false)
 const dialogTitle = ref('')
-const showSalesperson = ref(false)
-
 
 const tableColumns = reactive<TableColumn[]>([
   {
@@ -50,11 +49,35 @@ const tableColumns = reactive<TableColumn[]>([
     slots: {
       default: (data: any) => {
         const row = data.row
-        return (
+        if (row.uid == 0) {
+          return (
+            <>
+              <div>游客</div>
+            </>
+          )
+        } else {
+          return (
           <>
             <div>昵称: {row.real_name}</div>
-			<div>UID: {row.uid} </div>
-            <div>手机号: {row.phone}</div>
+            <div>UID: {row.uid} </div>
+            <div>手机号: {row.user_phone}</div>
+          </>
+        )
+        }
+        
+      }
+    }
+  },
+  {
+    field: 'store',
+    label: '门店',
+    minWidth: 100,
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        return (
+          <>
+            <div>{row.store.name}</div>
           </>
         )
       }
@@ -70,16 +93,52 @@ const tableColumns = reactive<TableColumn[]>([
         return (
           <>
             <div>昵称: {row.staff_name}</div>
-			<div>UID: {row.staff_id} </div>
+            <div>UID: {row.staff_id} </div>
           </>
         )
       }
     }
   },
   {
-    field: 'address',
-    label: '地址',
-    minWidth: 100
+    field: 'order_id',
+    label: '订单号',
+    minWidth: 150
+  },
+  {
+    field: 'info',
+    label: '商品信息',
+    minWidth: 200,
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        const info = row.info.map((item: any) => {
+          if (item.is_refund == 1) {
+            return (
+            <>
+              <div >{item.product_name} <ElButton type='text'>{item.cart_num * 1} {item.specs_name}</ElButton><ElButton type='text'>(¥{(item.price*1).toFixed(2)})</ElButton><ElButton type='text' style='color: red;'>(已退款¥{item.refund_price*1})</ElButton></div>
+            </>
+          )
+          } else {
+            return (
+            <>
+              <div>{item.product_name} <ElButton type='text'>{item.cart_num * 1} {item.specs_name}</ElButton><ElButton type='text'>(¥{(item.price*1).toFixed(2)})</ElButton></div>
+            </>
+          )
+          }
+          
+        })
+        return (
+          <>
+            {info}
+          </>
+        )
+        // return (
+        //   <>
+        //     <div>{row.pay_time ? row.pay_time_chs : ''}</div>
+        //   </>
+        // )
+      }
+    }
   },
   {
     field: 'total_price',
@@ -95,12 +154,13 @@ const tableColumns = reactive<TableColumn[]>([
         const row = data.row
         return (
           <>
-            <div>{row.pay_time?row.pay_time_chs: ''}</div>
+            <div>{row.pay_time ? row.pay_time_chs : ''}</div>
           </>
         )
       }
     }
   },
+  
   {
     field: 'paytype',
     label: '支付类型',
@@ -108,9 +168,29 @@ const tableColumns = reactive<TableColumn[]>([
     slots: {
       default: (data: any) => {
         const row = data.row
+        let pay_type = ''
+        switch (row.pay_type) {
+          case 'qudou':
+            pay_type = '趣豆'
+            break
+          case 'cash':
+            pay_type = '现金'
+            break
+          case 'card':
+            pay_type = '会员卡'
+            break
+          case 'weixin':
+            pay_type = '微信'
+            break
+          case 'alipay':
+            pay_type = '支付宝'
+            break
+          default:
+            pay_type = ''
+        }
         return (
           <>
-            <div>{row.pay_type}</div>
+            <div>{pay_type}</div>
           </>
         )
       }
@@ -127,6 +207,58 @@ const tableColumns = reactive<TableColumn[]>([
     label: '备注',
     minWidth: 140
   },
+  {
+    field: 'refund_price',
+    label: '退款金额',
+    minWidth: 100,
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        return (
+          <>
+            <div>{row.refund_price * 1 > 0 ? row.refund_price : ''}</div>
+          </>
+        )
+      }
+    }
+  },
+  {
+    field: 'refund_status',
+    label: '退款状态',
+    minWidth: 100,
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        let pay_type = ''// '0 未退款 1 申请中 2 已退款 3 部分退款',
+        switch (row.refund_status) {
+          case 0:
+            pay_type = ''
+            break
+          case 1:
+            pay_type = '申请中'
+            break
+          case 2:
+            pay_type = '已退款'
+            break
+          case 3:
+            pay_type = '部分退款'
+            break
+          default:
+            pay_type = ''
+        }
+        return (
+          <>
+            <div>{pay_type}</div>
+          </>
+        )
+      }
+    }
+  },
+  {
+    field: 'refund_reason',
+    label: '退款原因',
+    minWidth: 100
+  }
   // {
   //   field: 'action',
   //   label: '操作',
@@ -136,27 +268,48 @@ const tableColumns = reactive<TableColumn[]>([
   //   slots: {
   //     default: (data: any) => {
   //       const row = data.row;
-	// 	if(row.add_item.length > 0 && row.add_item[0].status == 0) {
-	// 		return (
-	// 		  <>
-	// 		  <ElButton type="primary" link size="small" onClick={() => action('edit', row)}>详情</ElButton>
-	// 		  <ElDivider direction="vertical" />
-	// 		  <ElButton type="primary" link size="small" onClick={() => action('auth', row)}>审核增项</ElButton>
-	// 		  </>
-	// 		)
-	// 	}else {
-	// 		return (
-	// 		  <>
-	// 		  <ElButton type="primary" link size="small" onClick={() => action('edit', row)}>详情</ElButton>
-	// 		  </>
-	// 		)
-	// 	}
-        
+  // 	if(row.add_item.length > 0 && row.add_item[0].status == 0) {
+  // 		return (
+  // 		  <>
+  // 		  <ElButton type="primary" link size="small" onClick={() => action('edit', row)}>详情</ElButton>
+  // 		  <ElDivider direction="vertical" />
+  // 		  <ElButton type="primary" link size="small" onClick={() => action('auth', row)}>审核增项</ElButton>
+  // 		  </>
+  // 		)
+  // 	}else {
+  // 		return (
+  // 		  <>
+  // 		  <ElButton type="primary" link size="small" onClick={() => action('edit', row)}>详情</ElButton>
+  // 		  </>
+  // 		)
+  // 	}
+
   //     }
   //   }
   // }
 ])
-
+const storeLoading = ref(false)
+const storeOptions = ref<any[]>([])
+  const getStore = async (query = '', id = '') => {
+  try {
+    storeLoading.value = true
+    const res = await getStoreList({ page: 1, limit: 1000, name: query, id, store: 1 })
+    if (res) {
+      storeOptions.value = res.data.data.map((item) => {
+        return {
+          value: item.id,
+          label: item.name
+        }
+      })
+    } else {
+      return []
+    }
+  } catch (error) {
+    console.log(error)
+  } finally {
+    storeLoading.value = false
+  }
+}
 const searchSchema = reactive<FormSchema[]>([
   {
     field: 'uid',
@@ -176,14 +329,55 @@ const searchSchema = reactive<FormSchema[]>([
     }
   },
   {
-    field: 'salesperson_id',
-    label: '业务员',
-    component: 'Input',
+    field: 'store_id',
+    label: '门店',
+    component: 'Select',
+    value: '',
     componentProps: {
-      type: 'number',
-      placeholder: '请选择业务员'
+      placeholder: '请选择',
+      options: storeOptions
+    }
+  },
+  {
+    field: 'pay_type',
+    label: '支付方式',
+    component: 'Select',
+    componentProps: {
+      placeholder: '请选择支付方式',
+      options: [
+        {
+          label: '微信',
+          value: 'weixin'
+        },
+        {
+          label: '支付宝',
+          value: 'alipay'
+        },
+        {
+          label: '会员卡',
+          value: 'card'
+        },
+        {
+          label: '现金',
+          value: 'cash'
+        },
+        {
+          label: '趣豆',
+          value: 'qudou'
+        }
+      ]
     }
   },
+  
+  // {
+  //   field: 'salesperson_id',
+  //   label: '业务员',
+  //   component: 'Input',
+  //   componentProps: {
+  //     type: 'number',
+  //     placeholder: '请选择业务员'
+  //   }
+  // },
   {
     field: 'order_id',
     label: '订单号',
@@ -219,7 +413,7 @@ const tabsConfig = reactive([
     title: '',
     total: 0,
     step: 0
-  },
+  }
   // {
   //   title: '设计师订单',
   //   total: 0,
@@ -259,39 +453,30 @@ const tabsConfigs = reactive([
   {
     title: '设计稿',
     total: 0,
-    step:1
+    step: 1
   },
   {
     title: '增项',
     total: 0,
-    step:2
-  },
+    step: 2
+  }
 ])
-const getLists = (e)=> {
-	console.log(e)
-}
 const checkedSalesperson = (e) => {
-	console.log(e,'x',e.value)
-	currentRow.value.salesperson_id = e.value.id;
-	currentRow.value.salesperson = e.value
-	getList()
+  console.log(e, 'x', e.value)
+  currentRow.value.salesperson_id = e.value.id
+  currentRow.value.salesperson = e.value
+  getList()
 }
 const checkedDesigner = (e) => {
-	console.log(e,'x',e.value)
-	currentRow.value.designer_id = e.value.id;
-	currentRow.value.designer = e.value
-	getList()
-}
-const checkedWorker = (e) => {
-	console.log(e,'x',e.value)
-	currentRow.value.worker_id = e.value.id;
-	currentRow.value.worker = e.value
-	getList()
+  console.log(e, 'x', e.value)
+  currentRow.value.designer_id = e.value.id
+  currentRow.value.designer = e.value
+  getList()
 }
 const passAddItem = () => {
-	isAuth.value = false
-	// currentRow.value.add_item[0].status = 1
-	getList()
+  isAuth.value = false
+  // currentRow.value.add_item[0].status = 1
+  getList()
 }
 const action = async (type: string, row?: any) => {
   // actionType.value = type
@@ -299,26 +484,29 @@ const action = async (type: string, row?: any) => {
   //   dialogTitle.value = t('exampleDemo.add')
   //   currentRow.value = undefined
   // }
-  
+
   //   console.log(currentRow, 'currentRow')
   // }
-	const res = await getOrderDetail(row.id)
-    if(type == 'edit') {
-		isEdit.value = true
-		dialogTitle.value = '详情'
-		currentRow.value = res.data
-		dialogVisible.value = true
-	}else if(type == 'auth') {
-		isAuth.value = true
-		activeNames.value = 2
-		dialogTitle.value = '详情'
-		currentRow.value = res.data
-		dialogVisible.value = true
-	}
+  const res = await getOrderDetail(row.id)
+  if (type == 'edit') {
+    isEdit.value = true
+    dialogTitle.value = '详情'
+    currentRow.value = res.data
+    dialogVisible.value = true
+  } else if (type == 'auth') {
+    isAuth.value = true
+    activeNames.value = 2
+    dialogTitle.value = '详情'
+    currentRow.value = res.data
+    dialogVisible.value = true
+  }
 }
 // const goAssignSalesman = async (id:number, data: any) => {
 // 	await assignSalesman(id,data)
 // }
+onMounted(() => {
+  getStore()
+})
 </script>
 
 <template>
@@ -350,30 +538,37 @@ const action = async (type: string, row?: any) => {
       }"
     />
   </ContentWrap>
-  
-  <ElDrawer
-      v-model="dialogVisible"
-      direction="rtl"
-	  size="50%"
-    >
-	<!-- // :title="dialogTitle" -->
-	<template #header="{ titleId, titleClass }">
-	      <h4 :id="titleId" :class="titleClass">{{dialogTitle}}</h4>
-	      <!-- <el-button type="danger" @click="close">
+
+  <ElDrawer v-model="dialogVisible" direction="rtl" size="50%">
+    <!-- // :title="dialogTitle" -->
+    <template #header="{ titleId, titleClass }">
+      <h4 :id="titleId" :class="titleClass">{{ dialogTitle }}</h4>
+      <!-- <el-button type="danger" @click="close">
 	        <el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>
 	        Close
 	      </el-button> -->
-	    </template>
-      <ElTabs v-model="activeNames" >
-        <ElTabPane
-          v-for="(item, index) in tabsConfigs"
-          :key="index"
-          :label="`${item.title}${item.total > 0 ? `(${item.total})` : ''}`"
-          :name="index"
-        />
-      </ElTabs>
-	  <Detail v-if="activeNames === 0" :current-row="currentRow" :isEdit="isEdit" @checkedSalesperson="checkedSalesperson" @checkedDesigner="checkedDesigner"/>
-	  <Draft v-if="activeNames === 1" :current-row="currentRow" />
-	  <addItem v-if="activeNames === 2" :current-row="currentRow" :isAuth="isAuth" @passAddItem="passAddItem"/>
-    </ElDrawer>
+    </template>
+    <ElTabs v-model="activeNames">
+      <ElTabPane
+        v-for="(item, index) in tabsConfigs"
+        :key="index"
+        :label="`${item.title}${item.total > 0 ? `(${item.total})` : ''}`"
+        :name="index"
+      />
+    </ElTabs>
+    <Detail
+      v-if="activeNames === 0"
+      :current-row="currentRow"
+      :isEdit="isEdit"
+      @checkedSalesperson="checkedSalesperson"
+      @checkedDesigner="checkedDesigner"
+    />
+    <Draft v-if="activeNames === 1" :current-row="currentRow" />
+    <addItem
+      v-if="activeNames === 2"
+      :current-row="currentRow"
+      :isAuth="isAuth"
+      @passAddItem="passAddItem"
+    />
+  </ElDrawer>
 </template>

+ 2 - 2
src/views/Store/Role/Role.vue

@@ -112,11 +112,11 @@ const searchSchema = reactive<FormSchema[]>([
           value: ''
         },
         {
-          label: '不显示',
+          label: '禁用',
           value: 0
         },
         {
-          label: '显示',
+          label: '启用',
           value: 1
         }
       ]

+ 174 - 0
src/views/Store/area/components/Write.vue

@@ -0,0 +1,174 @@
+<script setup lang="tsx">
+import { watch, ref, onMounted } from 'vue'
+import {  productUnit } from '@/api/goods/types'
+import {
+  getProductUnitDetail,
+  addProductUnit,
+  putProductUnit,
+  getUnitList
+} from '@/api/goods'
+import {
+  ElForm,
+  ElFormItem,
+  ElInput,
+  ElMessage,
+  ElRadioGroup,
+  ElRadio,
+  ElSelect,
+  ElOption
+} from 'element-plus'
+import type {  FormInstance } from 'element-plus'
+import { Dialog } from '@/components/Dialog'
+import { useI18n } from '@/hooks/web/useI18n'
+const { t } = useI18n()
+
+const props = defineProps({
+  id: {
+    type: Number,
+    default: 0
+  },
+  title: {
+    type: String,
+    default: ''
+  }
+})
+const modelValue = defineModel<boolean>()
+const ruleFormRef = ref<FormInstance>()
+const emit = defineEmits(['submit'])
+const submit = async () => {
+  if (ruleFormRef.value) {
+    const valid = await ruleFormRef.value.validate((valid, fields) => {
+      // console.log(fields, 'fields')
+      if (!valid) {
+        console.log('error submit!', fields)
+      }
+    })
+    if (valid) {
+      loadingData.value = true
+      try {
+        let re: any = {}
+        if (form.value.id > 0) {
+          re = await putProductUnit(form.value)
+        } else if (form.value.id == 0) {
+          re = await addProductUnit(form.value)
+        }
+        if (re.status == 200) {
+          ElMessage({
+            showClose: true,
+            message: '添加成功',
+            type: 'success'
+          })
+        }
+        getUnitLists()
+        form.value = {
+          name: '',
+          id: 0,
+          type: 'area',
+          pid: 0,
+          sort: 0,
+          is_show: 1,
+          path: '',
+          is_weigh: 0
+        }
+        emit('submit')
+      } catch (error) {
+        console.log(error)
+      } finally {
+        loadingData.value = false
+      }
+    }
+  }
+}
+const loadingData = ref(false)
+watch(
+  () => props.id,
+  async (value) => {
+    console.log('zhixin');
+    
+    if (value * 1 === 0) return
+    loadingData.value = true
+    const res = await getProductUnitDetail(value)
+    form.value = res.data
+    loadingData.value = false
+  },
+  {
+    deep: true,
+    immediate: true
+  }
+)
+const form = ref<productUnit>({
+  name: '',
+  id: 0,
+  type: 'area',
+  pid: 0,
+  sort: 0,
+  is_show: 1,
+  path: '',
+  is_weigh: 0
+})
+const options = ref<any[]>([])
+const getUnitLists = async () => {
+  // getUnitList()
+  let res = await getUnitList({
+    page: 1,
+    limit: 100,
+    type: 'area',
+    is_show: 1,
+    pid: 0
+  })
+  options.value = [{ value: 0, label: '顶级' }].concat(getOp(res.data.list))
+}
+const getOp = (arr: any[]) => {
+  let arr1 = arr.map((item) => {
+    let obj = {
+      value: item.id,
+      label: item.name
+    }
+    return obj
+  })
+  return arr1
+}
+onMounted(() => {
+  getUnitLists()
+})
+</script>
+
+<template>
+  <Dialog v-model="modelValue" :title="title" width="600px">
+    <el-form v-loading="loadingData" ref="ruleFormRef" :model="form" label-width="auto">
+      <el-form-item
+        prop="name"
+        label="区域名称"
+        :rules="[{ required: true, message: '区域名称', trigger: 'blur' }]"
+      >
+        <el-input v-model="form.name" />
+      </el-form-item>
+      <!-- <el-cascader :options="options" :props="props1" clearable /> -->
+      <el-form-item prop="pid" label="上级区域">
+        <el-select v-model="form.pid" class="m-2" placeholder="Select" size="large">
+          <el-option
+            v-for="item in options"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="sort" label="排序">
+        <el-input v-model="form.sort" />
+      </el-form-item>
+      <el-form-item prop="is_show" label="是否显示">
+        <el-radio-group v-model="form.is_show" class="ml-4">
+          <el-radio :label="1" size="large">是</el-radio>
+          <el-radio :label="0" size="large">否</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <BaseButton type="primary" :loading="loadingData" @click="submit">
+        {{ t('exampleDemo.save') }}
+      </BaseButton>
+      <BaseButton @click="modelValue = false">{{ t('dialogDemo.close') }}</BaseButton>
+    </template>
+  </Dialog>
+</template>

+ 245 - 0
src/views/Store/area/index.vue

@@ -0,0 +1,245 @@
+<script setup lang="tsx">
+import { reactive, ref, unref } from 'vue'
+import { useTable } from '@/hooks/web/useTable'
+import { useI18n } from '@/hooks/web/useI18n'
+import { Table, TableColumn } from '@/components/Table'
+import { ContentWrap } from '@/components/ContentWrap'
+import { BaseButton } from '@/components/Button'
+import { ElDivider, ElMessage, ElMessageBox,ElTag } from 'element-plus'
+import Write from './components/Write.vue'
+import { delProductUnit,getUnitList } from '@/api/goods'
+import { FormSchema } from '@/components/Form'
+import { Search } from '@/components/Search'
+
+const { t } = useI18n()
+
+const { tableRegister, tableState, tableMethods } = useTable({
+  fetchDataApi: async () => {
+    const res = await getUnitList({
+      ...searchParams.value,
+      page: unref(currentPage) || 1,
+      limit: unref(pageSize) || 10,
+    })
+    return {
+      list: res.data.list,
+      total: res.data.count || 0
+    }
+  }
+})
+
+const { dataList, loading, total, currentPage, pageSize } = tableState
+const { getList } = tableMethods
+
+const tableColumns = reactive<TableColumn[]>([
+  {
+    field: 'id',
+    label: 'ID',
+    width: 100
+  },
+  {
+    field: 'name',
+    label: '区域名称',
+    minWidth: 100
+  },
+  // {
+  //   field: 'is_weigh',
+  //   label: '是否称重',
+  //   width: 200,
+  //   align: 'center',
+  //   slots: {
+  //     default: (data: any) => {
+  //       const row = data.row
+  //       if (row.is_weigh == 1) {
+  //         return (
+  //           <>
+  //         <ElTag >是</ElTag></>
+  //         )
+  //       } else {
+  //         return (
+  //         <>
+  //           <ElTag type="info">否</ElTag></>
+  //       )
+  //       }
+        
+  //     }
+  //   }
+  // },
+  {
+    field: 'is_show',
+    label: '是否显示',
+    width: 200,
+    align: 'center',
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        if (row.is_show == 1) {
+          return (
+            <>
+          <ElTag >是</ElTag></>
+          )
+        } else {
+          return (
+          <>
+            <ElTag type="info">否</ElTag></>
+        )
+        }
+      }
+    }
+  },
+  {
+    field: 'action',
+    label: t('userDemo.action'),
+    width: 200,
+    fixed: 'right',
+    align: 'center',
+    headerAlign: 'center',
+    slots: {
+      default: (data: any) => {
+        const row = data.row
+        return (
+          <>
+            <BaseButton link size="small" type="primary" onClick={() => action('edit', row)}>
+              编辑
+            </BaseButton>
+            <ElDivider direction="vertical" />
+            <BaseButton link size="small" type="danger" onClick={() => delAction(row)}>
+              删除
+            </BaseButton>
+          </>
+        )
+      }
+    }
+  }
+])
+
+const dialogVisible = ref(false)
+const currentRow = ref(0)
+const dialogTitle = ref('')
+const actionType = ref('')
+
+const action = async (type: string, row?: any) => {
+  actionType.value = type
+  if (type == 'add') {
+    dialogTitle.value = t('exampleDemo.add')
+    currentRow.value = 0
+  }
+  if (type == 'edit') {
+    dialogTitle.value = t('exampleDemo.edit')
+    currentRow.value = row.id
+  }
+  dialogVisible.value = true
+}
+const delAction = (row: any) => {
+  ElMessageBox.confirm('删除后无法恢复,是否删除?', {
+    confirmButtonText: '删除',
+    cancelButtonText: '取消',
+    type: 'warning'
+  })
+    .then(async () => {
+      const re = await delProductUnit(row.id)
+      if (re) {
+        ElMessage({
+          showClose: true,
+          message: '删除成功',
+          type: 'success'
+        })
+      }
+      await getList()
+    })
+    .catch(() => {})
+}
+const save = async () => {
+  getList()
+  dialogVisible.value = false
+}
+const searchSchema = reactive<FormSchema[]>([
+  {
+    field: 'name',
+    label: '区域名称',
+    component: 'Input',
+    componentProps: {
+      placeholder: '请输入区域名称'
+    }
+  },
+  {
+    field: 'type',
+    label: '类型',
+    value: 'area',
+    component: 'Input',
+    hidden: true,
+    componentProps: {
+      placeholder: ''
+    }
+  },
+  {
+    field: 'pid',
+    label: '类型',
+    value: 0,
+    hidden: true,
+    componentProps: {
+      placeholder: ''
+    }
+  },
+
+  {
+    field: 'is_show',
+    label: '是否显示',
+    component: 'Select',
+    value: -1,
+    componentProps: {
+      placeholder: '全部',
+      options: [
+        {
+          label: '全部',
+          value: -1
+        },
+        {
+          label: '显示',
+          value: 1
+        },
+        {
+          label: '隐藏',
+          value: 0
+        }
+      ]
+    }
+  }
+])
+const searchParams = ref<{ type: string,name: string,pid: number }>({ type: 'area',name: '',pid: 0 })
+
+const setSearchParams = (data: any) => {
+  searchParams.value = data
+  getList()
+}
+</script>
+
+<template>
+  <ContentWrap>
+    <Search :schema="searchSchema" @reset="setSearchParams" @search="setSearchParams" />
+
+    <div class="mb-10px">
+      <BaseButton type="primary" @click="action('add')">{{ t('exampleDemo.add') }}</BaseButton>
+    </div>
+    <Table
+      v-model:current-page="currentPage"
+      v-model:page-size="pageSize"
+      :columns="tableColumns"
+      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+      stripe
+      :data="dataList"
+      :loading="loading"
+      @register="tableRegister"
+      :pagination="{
+        total
+      }"
+    />
+  </ContentWrap>
+
+  <Write
+    v-model="dialogVisible"
+    :title="dialogTitle"
+    ref="writeRef"
+    :id="currentRow"
+    @submit="save"
+  />
+</template>

+ 68 - 1
src/views/Store/list/components/Write.vue

@@ -12,9 +12,16 @@ import { mapAddressData } from '@/api/system/admin/types'
 // import { BaseButton } from '@/components/Button'
 import { StoreButtom } from '@/components/StoreList'
 import { getRoleListApi } from '@/api/system/role'
+import { getUnitList } from '@/api/goods'
 
+interface op {
+  label: string
+  value: number
+}
 const mapKey = ref('')
 const roleList = ref([])
+const areaList = ref<op[]>([])
+
 const actionAddress = ref<mapAddressData>()
 const { required } = useValidator()
 const center = ref({ lat: 28.655759, lng: 121.420808 })
@@ -37,6 +44,7 @@ const rules = reactive<FormRules>({
   manager_name: [required('请填写店长名称')],
   valid_range: [required('请填写有效距离')],
   roles: [required('请选择角色')],
+  configure_id: [required('请选择区域')],
   store_account: [
     {
       required: true,
@@ -107,7 +115,35 @@ onMounted(async () => {
       label: item.role_name
     }
   })
-  console.log(roleList,'roleListroleListroleListroleList')
+  const data1 = await getUnitList({ page: 1, limit: 100, type: 'area',pid: 0})
+  // areaList.value = data1.data.list.map((item) => {
+
+  //   return {
+  //     value: item.id,
+  //     label: item.name,
+  //   }
+  // })
+  data1.data.list.forEach(element => {
+    if (element.children.length == 0) {
+      areaList.value.push({
+        value: element.id,
+        label: element.name,
+      })
+    } else {
+      areaList.value.push({
+        value: element.id,
+        label: element.name,
+      })
+      element.children.forEach(element1 => {
+        areaList.value.push({
+          value: element1.id,
+          label: '|__' + element1.name,
+        })
+      });
+    }
+  });
+  console.log(areaList,'areaListareaListareaListareaList')
+  await nextTick()
   await nextTick()
   if (rules && rules.store_account) {
     rules.store_account[0].required = required
@@ -387,6 +423,37 @@ const formSchema = ref<FormSchema[]>([
       }
     }
   },
+  {
+    field: 'configure_id',
+    label: '区域',
+    component: 'Select',
+    formItemProps: {
+      slots: {
+        default: (data) => {
+          return (
+            <>
+              <ElSelect
+                v-model={data.configure_id}
+                placeholder="请选择区域"
+                size="large"
+                style="width: 240px"
+              >
+                {
+                  areaList.value.map((item: {value: number,label: string}) => {
+                    return (
+                      <>
+                        <ElOption value={item.value} label={item.label}></ElOption>
+                      </>
+                    )
+                  })
+                }
+              </ElSelect>
+            </>
+          )
+        }
+      }
+    }
+  },
   {
     field: 'receiver_uid',
     label: '店长UID',

+ 37 - 7
src/views/Store/list/index.vue

@@ -1,6 +1,6 @@
 <script setup lang="tsx">
 import { reactive, ref, unref, useTemplateRef } from 'vue'
-import { getStoreList, addStore, editStore, delStore } from '@/api/store'
+import { getStoreList, addStore, editStore, delStore, storeExport } from '@/api/store'
 import { useTable } from '@/hooks/web/useTable'
 import { useI18n } from '@/hooks/web/useI18n'
 import { Table, TableColumn } from '@/components/Table'
@@ -12,6 +12,7 @@ import { BaseButton } from '@/components/Button'
 import { ElDivider, ElMessage, ElMessageBox, ElTag } from 'element-plus'
 import { TableImage } from '@/components/tableImage'
 import Write from './components/Write.vue'
+import createWorkBook from '@/utils/newToExcel'
 
 const { t } = useI18n()
 
@@ -231,6 +232,7 @@ const action = async (type: string, row?: any) => {
   if (type == 'add') {
     dialogTitle.value = t('exampleDemo.add')
     currentRow.value = undefined
+    dialogVisible.value = true
   }
   if (type == 'edit') {
     dialogTitle.value = t('exampleDemo.edit')
@@ -264,12 +266,36 @@ const action = async (type: string, row?: any) => {
       huifu_id: row.huifu_id,
       appsecret: row.appsecret,
       cost: row.cost,
-      roles: row.roles*1
-
+      roles: row.roles * 1,
+      configure_id: row.configure_id
     }
-    console.log(currentRow, 'currentRow')
+    dialogVisible.value = true
+  }
+  if (type == 'export') {
+    storeExport().then((res: any) => {
+      let data = res.data
+      let arr = [] as any[]
+      data.export.forEach((item) => {
+        let arr1 = [] as any[]
+        for (let i in item) {
+          if (i == 'type') {
+          arr1.push(item[i] == 1 ? '自营' : '加盟')         
+          } else {
+          arr1.push(item[i])         
+            
+          }
+        }
+        arr.push(arr1)
+      })
+      createWorkBook(data.header, data.filename,arr, [], data.filename)
+      // createWorkBook()
+      // ElMessage({
+      //   showClose: true,
+      //   message: '导出成功',
+      //   type: 'success'
+      // })
+    })
   }
-  dialogVisible.value = true
 }
 const delAction = (row: any) => {
   ElMessageBox.confirm('删除后无法恢复,是否删除?', {
@@ -301,7 +327,7 @@ const save = async () => {
     const data: any = {
       // roles: formData.roles,
       appid: formData.appid,
-      loss_sale: formData.loss_sale?1:0,
+      loss_sale: formData.loss_sale ? 1 : 0,
       receiver_uid: formData.receiver_uid,
       huifu_id: formData.huifu_id,
       appsecret: formData.appsecret,
@@ -330,8 +356,11 @@ const save = async () => {
       auth_code: formData.auth_code,
       auth_code_end_time: formData.auth_code_end_time,
       cost: formData.cost,
-      roles: formData.roles + ''
+      roles: formData.roles + '',
+      configure_id: formData.configure_id
     }
+    // console.log(data);
+
     try {
       if (actionType.value === 'edit') {
         await editStore(data)
@@ -360,6 +389,7 @@ const save = async () => {
     <Search :schema="searchSchema" @reset="setSearchParams" @search="setSearchParams" />
     <div class="mb-10px">
       <BaseButton type="primary" @click="action('add')">{{ t('exampleDemo.add') }}</BaseButton>
+      <BaseButton @click="action('export')">导出</BaseButton>
     </div>
     <Table
       v-model:current-page="currentPage"

+ 10 - 9
src/views/System/class/index.vue

@@ -136,6 +136,15 @@ const tableColumns = reactive<TableColumn[]>([
 ])
 
 const searchSchema = reactive<FormSchema[]>([
+  {
+    field: 'title',
+    label: '名称',
+    component: 'Input',
+    value: '',
+    componentProps: {
+      placeholder: '请输入名称'
+    }
+  },
   {
     field: 'status',
     label: t('menu.status'),
@@ -178,15 +187,7 @@ const searchSchema = reactive<FormSchema[]>([
       ]
     }
   },
-  {
-    field: 'title',
-    label: '搜索',
-    component: 'Input',
-    value: '',
-    componentProps: {
-      placeholder: '请输入姓名或者账号'
-    }
-  }
+  
 ])
 
 const searchParams = ref({ status: '', title: '', is_store: '' })

+ 8 - 6
src/views/User/list/components/DetailFrom.vue

@@ -159,12 +159,12 @@ const userRecordList = ref([
         field: 'nickname'
       },
       {
-        label: '用户手机号',
-        field: 'phone'
+        label: '推广人数',
+        field: 'spread_count'
       },
       {
-        label: '用户余额',
-        field: 'now_money'
+        label: '来源',
+        field: 'user_type'
       }
     ]
   }
@@ -180,6 +180,8 @@ const changeTable = (row: any) => {
   }
 }
 const getList = async (element) => {
+  console.log(element,'element');
+  
   try {
     if (!element.loading || element.initLoading) {
       element.loading = true
@@ -191,8 +193,8 @@ const getList = async (element) => {
           },
           props.userDetail.uid
         )
-        element.data = res.data.list
-        element.total = res.data.total
+        element.data = res.data
+        element.total = res.data.length
       } else if (element.type == '2') {
         const res = await getBalanceLog(
           {

+ 1 - 1
src/views/User/list/components/Write.vue

@@ -43,7 +43,7 @@ const formSchema = ref<FormSchema[]>([
     component: 'Input',
     componentProps: {
       type: 'number',
-      placeholder: '请输入管理员账号'
+      placeholder: '请输入手机号'
     }
   },
   {

+ 1 - 1
src/views/User/list/index.vue

@@ -75,7 +75,7 @@ onMounted(async () => {
     // 处理 userLevel 数据
     const processLevelData = (data) =>
       data.list.map((res) => ({
-        label: res.name,
+        label: res.name +  (res.is_show == 1 ? '' : '(已隐藏)'),
         value: res.id
       }))
 

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff