6 Commits acded512f9 ... 65f8a4cef2

Auteur SHA1 Message Date
  xutongzee 65f8a4cef2 add vconfole packages il y a 1 an
  xutongzee f63603d2c7 ignore il y a 1 an
  xutongzee 52929174c1 cms il y a 1 an
  xutongzee ec90d9894a 申请表单中。 申请流程 抄送更新 il y a 1 an
  xutongzee d93b6a957c part code il y a 1 an
  xutongzee f0bbbc273b feat: 完成商品新增和修改 il y a 1 an

+ 14 - 19
TODO.md

@@ -17,7 +17,7 @@
 
 ### 缺少明细的页面
 
-- 申购 1
+- 申购 1 - 欠缺导入功能
 - 入库 3
 - 领用(已添加 4
 
@@ -32,19 +32,11 @@
 ## RearEnd Bugs
 
 - [ ] 批量导入接口[导入 excel 文件]缺失, 需要下载相对应的 excel 模板文件接口
-- [x] 商品库接口。
-- [x] 商品库分类接口(2 级) (3 级-带产品)
-- [x] ~~根据商品 id 查询详情的接口~~
 - [ ] 商品库搜索商品接口
 
--- 2023/12/12 --
+--- 2023/12/16 ---
 
-- [x] 分类接口需要根据字段 展示全部分类数据或者 展示有商品的数据
-- [x] 分类规格数据
-
--- 2023/12/13 --
-
-- [ ] 新增商品。 修改商品时 需要分类中文展示
+- [ ] 欠缺导入模板说明(采购、领用)
 
 ## Warning
 
@@ -52,15 +44,18 @@
 
 # 今日完成
 
-- 更新个人接口接口字段。
+- [x] 申购导入模板接口调试完成
+- [x] 申购模板下载模板
+
+- [x] 领用导入模板接口调试完成
+- [x] 领用模板下载模板
+- [ ] 领用明细不需要价格 UI
 
 ## 流程
 
-- [ ] 合同呈批 type = 9
+- [ ] 申购申请 module = 1
+- [x] 维修流程 module = 8
+- [ ] 合同呈批 module = 9
 
-- [ ] 维修流程 type = 8
-  - [x] 报表填写流程
-  - [x] 渲染展示字段
-  - [x] 回填表单
-  - [x] 审核小功能
-  - [x] 审核人员修改可以
+- [ ] 申请人 用车
+- [ ] 申请人 请假

+ 31 - 0
package-lock.json

@@ -36,6 +36,7 @@
         "postcss": "^8.4.31",
         "postcss-loader": "^4.3.0",
         "postcss-pxtorem": "^5.1.1",
+        "vconsole": "^3.15.1",
         "vue-template-compiler": "^2.6.11"
       }
     },
@@ -5063,6 +5064,18 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/copy-text-to-clipboard": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz",
+      "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/copy-webpack-plugin": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz",
@@ -10360,6 +10373,12 @@
       "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==",
       "dev": true
     },
+    "node_modules/mutation-observer": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz",
+      "integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==",
+      "dev": true
+    },
     "node_modules/mute-stream": {
       "version": "0.0.8",
       "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
@@ -15798,6 +15817,18 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/vconsole": {
+      "version": "3.15.1",
+      "resolved": "https://registry.npmjs.org/vconsole/-/vconsole-3.15.1.tgz",
+      "integrity": "sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.17.2",
+        "copy-text-to-clipboard": "^3.0.1",
+        "core-js": "^3.11.0",
+        "mutation-observer": "^1.0.3"
+      }
+    },
     "node_modules/vendors": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",

+ 1 - 0
package.json

@@ -36,6 +36,7 @@
     "postcss": "^8.4.31",
     "postcss-loader": "^4.3.0",
     "postcss-pxtorem": "^5.1.1",
+    "vconsole": "^3.15.1",
     "vue-template-compiler": "^2.6.11"
   },
   "eslintConfig": {

+ 11 - 0
record.md

@@ -0,0 +1,11 @@
+# 深圳市第二特殊教育学校
+
+> h5微应用
+
+```shell
+AgentId=2062807790
+AppKey=dingekepwoyycxfbtyvg
+AppSecret=EjM9WohvKHo3eNqZGGbQHhbjM80QzapdC_f_reYiOCyEFOtaG1qoG2KzEfpSoLWe
+sever=120.79.86.50
+
+```

+ 8 - 0
src/api/approve.js

@@ -36,4 +36,12 @@ export const editApprove = data => (request({
     data,
     method: 'POST',
     url: 'approve/edit'
+}))
+
+/**
+ * @description 获取用户审批待处理统计
+ */
+export const getUserApproveCount = () => (request({
+    method: 'POST',
+    url: 'approve/get_count',
 }))

+ 7 - 0
src/api/approveinfo.js

@@ -45,3 +45,10 @@ export const putCancel = data => (request({
     url: 'approveinfo/cancel',
     data
 }))
+
+// 申请人列表
+export const getUserList = data => (request({
+    method: 'POST',
+    url: 'approveinfo/get_user_list',
+    data
+}))

+ 23 - 0
src/api/common.js

@@ -14,3 +14,26 @@ export const getAuthentication = () => (request({
     method: "POST",
     url: ""
 }))
+
+
+/**
+ * 导入模板路径
+ * @param {Object} data 导入模板路径
+ * @returns Promise
+ */
+export const postImportFile = data => (request({
+    data,
+    method: "POST",
+    url: "common/import"
+}))
+
+/**
+ * 获取导入的模板链接
+ * @param {Object} data 定义导入模板的module
+ * @returns Promise
+ */
+export const getImportTemplate = data => (request({
+    data,
+    method: "POST",
+    url: "common/get_import_template"
+}))

+ 1 - 9
src/api/member.js

@@ -23,12 +23,4 @@ export const putUserInfo = (data) => (request({
     data,
     method: 'POST',
     url: 'member/edit'
-}))
-
-/**
- * @description 获取用户审批待处理统计
- */
-export const getUserApproveCount = () => (request({
-    method: 'POST',
-    url: 'member/get_count',
-}))
+}))

+ 10 - 0
src/main.js

@@ -1,3 +1,4 @@
+import vConsole from 'vconsole'
 import Vue from 'vue'
 import router from './router'
 import store from './store'
@@ -13,6 +14,15 @@ import App from './App.vue'
 
 import 'amfe-flexible'
 
+if (process.env.NODE_ENV == 'development') {
+  // https://www.npmjs.com/package/vconsole
+  // 可以添加`options`进行配置项目
+  new vConsole()
+  // console.log('%c 开发环境 CONF >>>', 'background: blue; color: #fff', );
+  // import VConsole from 'vconsole'
+  // TODO: 配置开发环境 辅助工具
+}
+
 Vue.config.productionTip = false
 
 new Vue({

+ 7 - 4
src/router/index.js

@@ -32,7 +32,6 @@ const routes = [
   },
 
   {
-    // NOTE: 自己书写外部出差人员
     path: '/applyfor/peers-out-form',
     name: 'PeersOutForm',
     component: () => import(/* webpackChunkName: "index" */ '../views/applyfor/peersOutForm.vue')
@@ -58,10 +57,14 @@ const routes = [
     name: 'GoodsSpeci',
     component: () => import(/* webpackChunkName: "applyfor" */ '../views/applyfor/goods-specifications.vue')
   },
+
   {
-    path: '/applyfor/goods-unit',
-    name: 'GoodsUnit',
-    component: () => import(/* webpackChunkName: "applyfor" */ '../views/applyfor/goods-unit-price.vue')
+    meta: {
+      title: '申请人列表'
+    },
+    path: '/applyfor/apply-of-user',
+    name: 'ApplyUser',
+    component: () => import(/* webpackChunkName: "applyfor" */ '../views/applyfor/applyOfUser.vue')
   },
 
   // NOTE:我的审核状态

+ 2 - 0
src/store/modules/enum.js

@@ -63,6 +63,8 @@ const getters = {
     getDegreeText: state => id => getKeyToTxt(state.degreeList, id),
     // NOTE: 获取维修分类
     getMaintainText: state => id => getKeyToTxt(state.maintainTypeList, id),
+    getPayTypeText: state => id => getKeyToTxt(state.applyPayTypeList, id),
+    getapplyTypeText: state => id => getKeyToTxt(state.applyTypeList, id),
 }
 
 const mutations = {

+ 1 - 1
src/store/modules/user.js

@@ -11,7 +11,7 @@ const state = {
     mobile: '',
     userinfo: {},
     signatureStateText: '',  // 个签
-    token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiI4NSIsImlzcyI6Imh0dHBzOlwvXC96YWluLmNvbSIsImF1ZCI6Imh0dHBzOlwvXC96YWluLmNvbSIsImlhdCI6MTY5ODMxMjI4NSwibmJmIjoxNjk4MzEyMjg1LCJleHAiOjE3MjQyMzIyODV9.ziAXs6DiZKGGjtPuaCZ6Vfpv6Ki_deZhFPnDDLjAJUg',
+    token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiIxOSIsImlzcyI6Imh0dHBzOlwvXC96YWluLmNvbSIsImF1ZCI6Imh0dHBzOlwvXC96YWluLmNvbSIsImlhdCI6MTcwMjY5NzQ0NCwibmJmIjoxNzAyNjk3NDQ0LCJleHAiOjE3Mjg2MTc0NDR9.BOU8yu57KZrgUbcIGuS0a8AB91oLhH6nHawxYUQwt7U',
 }
 
 const getters = {

+ 1 - 1
src/styles/variables.less

@@ -11,7 +11,7 @@
 @text-bold-color: rgba(51, 51, 51, 1);
 
 @link-font-size: 16px;
-@link-color: rgba(0, 122, 255, 1);
+@link-color: #007aff;
 
 @status-success-color: rgba(82, 196, 26, 1);
 @status-warning-color: rgba(250, 173, 21, 1);

+ 51 - 1
src/utils/applyfor-item.js

@@ -6,14 +6,64 @@ import store from "@/store"
 // const degree2Txt = store.getters['enum/getDegreeText']
 const maintainTypeList = store.getters['enum/getMaintainText']
 
+const getPayTypeText = store.getters["enum/getPayTypeText"]
+const getapplyTypeText = store.getters["enum/getapplyTypeText"]
+
+
 function getModule1(data){
-  const { create_at } = data
+  const { order_no, department_data, create_at, module_info, apply_user } = data
   // TODO: 待完成
   return [
     {
+      title: '审批编号',
+      value: order_no
+    },
+    // 合同编号
+    {
+      title: '所在部门',
+      value: department_data.map(department => (department.name)).join(',')
+    },
+    {
       title: '申请日期',
       value: create_at
     },
+    {
+      title: '申请人',
+      value: apply_user.name
+    },
+    {
+      title: '申请事由',
+      value: module_info.reason
+    },
+    {
+      title: '申购类型',
+      value: getapplyTypeText(module_info.type)
+    },
+    // TODO: 待办
+    // 申购明细
+    {
+      title: '总金额',
+      value: module_info.total_amount
+    },
+    {
+      title: '预计申购完成日期',
+      value: module_info.apply_date
+    },
+    {
+      title: '附件材料',
+      value: "@TODO"
+    },
+    module_info.images_text.length ? {
+      type: 'images',
+      title: '图片',
+      value: module_info.images_text.map(img => ({
+        url: img
+      }))
+    } : undefined,
+    {
+      title: '支付方式',
+      value: getPayTypeText(module_info.pay_type)
+    },
   ]
 }
 

+ 3 - 1
src/utils/import-vant.js

@@ -26,11 +26,13 @@ import {
     Checkbox,
     Radio,
     RadioGroup,
-    Stepper
+    Stepper,
+    Tag
 } from 'vant'
 
 Vue.use(Tab).use(Tabs).use(Popup).use(Toast).use(Field).use(Button).use(NavBar).use(Icon).use(Tabbar).use(TabbarItem).use(Picker)
 .use(Uploader).use(Calendar).use(DatetimePicker).use(ActionSheet).use(Switch).use(List).use(Dialog).use(Checkbox).use(Radio).use(RadioGroup).use(Stepper)
+.use(Tag)
 
 
 Vue.use(ImagePreview)

+ 0 - 3
src/utils/util.js

@@ -44,10 +44,7 @@ export const getStringTye = variable => (Object.prototype.toString.call(variable
 export const getStaticLinkInfo = url => {
     // https://chaoting-washing.oss-cn-zhangjiakou.aliyuncs.com/dd808164257b2fc2/a729087658ff1ef0.pdf
     let regexp = /^(http[s]:\/\/.*\.com)(.*?)(([\w\d\s.]*?)\.(\w*))$/i;
-    console.log('%c getStaticLinkInfo url >>>', 'background: blue; color: #fff', url);
-    
     let matchArrs = url.match(regexp);
-    
     let name = 'unknow'
     let suffix = 'unknow'
     let path = ''

+ 30 - 18
src/views/My.vue

@@ -26,21 +26,14 @@
         <!-- 业务面 -->
         <div class="pbn-box">
             <div class="scroll-box">
-                <div
-                    class="pbn__item"
-                    v-for="(item, idx) in renderList"
-                    :key="idx"
-                    @click="handleGoApplyOfState(item)"
-                    >
+                <div class="pbn__item" v-for="(item, idx) in renderList" :key="idx" @click="handleGoApplyOfState(item)">
                     <div class="pbn__item__pic">
                         <img :src="item.pic" :alt="item.tit">
                     </div>
                     <div class="pbn__item__tit">{{ item.tit }}</div>
                     <div class="pbn__item__ignore">
                         <div class="pbn__item__msg" v-show="item.msgNum >= 1"><span>待处理{{ item.msgNum }}条</span></div>
-                        <div class="pbn__item__icon-arrow-right">
-                            <van-icon name="arrow" size="18" color="#C2C2C2" />
-                        </div>
+                        <van-icon name="arrow" size="18" color="#C2C2C2" />
                     </div>
                 </div>
             </div>
@@ -50,7 +43,7 @@
 </template>
 
 <script>
-import { getUserApproveCount } from '@/api/member'
+import { getUserApproveCount } from '@/api/approve'
 
 import { mapState, mapGetters } from 'vuex'
 
@@ -67,7 +60,7 @@ export default {
             departments: 'getDepartments'
         })
     },
-    data () {
+    data() {
         return {
             renderList: [],
             list: [
@@ -118,19 +111,19 @@ export default {
             ]
         }
     },
-    async created () {
+    async created() {
         // NOTE: 进入当前页面更新用户信息
         await this.$store.dispatch('user/getUserInfo')
         this.__init__()
     },
 
     methods: {
-        __init__ () {
+        __init__() {
             this.get_approve_count()
         },
 
         // NOTE: 获取待处理信息
-        async get_approve_count () {
+        async get_approve_count() {
             try {
                 const result = await getUserApproveCount()
                 if (result.code === 1) {
@@ -143,13 +136,13 @@ export default {
                         tit: item.module_text
                     }))
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('get_approve_count error>', e);
             }
         },
 
         // NOTE: 跳转申请状态列表
-        handleGoApplyOfState (row) {
+        handleGoApplyOfState(row) {
             this.$router.push({
                 name: 'ApplyState',
                 query: {
@@ -160,7 +153,7 @@ export default {
         handleGoSetting() {
             this.handleGoUserInfo()
         },
-        handleGoUserInfo () {
+        handleGoUserInfo() {
             this.$router.push({
                 name: 'Userinfo'
             })
@@ -180,12 +173,14 @@ export default {
     flex-direction: column;
     justify-items: auto;
     user-select: none;
+
     .setting {
         text-align: right;
         padding: 4px 0;
         font-size: @text-secondery-size;
         color: rgba(10, 22, 41, 1);
     }
+
     .info {
         display: flex;
         flex-direction: row;
@@ -193,6 +188,7 @@ export default {
         padding-bottom: 16px;
         border-bottom: 1px solid rgba(151, 151, 151, 0.2);
     }
+
     .pbn-box {
         flex: 1;
         height: 100%;
@@ -209,26 +205,31 @@ export default {
         border-radius: 8px;
         overflow: hidden;
         margin-right: 15px;
+
         img {
             width: 100%;
             height: 100%;
         }
     }
+
     &__infobox {
         flex: 1;
         display: flex;
         flex-direction: column;
         align-items: flex-start;
     }
+
     &__name {
         font-size: @text-common-size;
         font-weight: 500;
         line-height: 22px;
         color: rgba(10, 22, 41, 1);
     }
+
     &__row {
         font-size: 24px;
         padding-bottom: 4px;
+
         span {
             display: inline-block;
             font-size: 12px;
@@ -236,19 +237,23 @@ export default {
             font-weight: 500;
             color: rgba(114, 114, 115, 1);
         }
+
         &-schoolname {
             margin-right: 8px;
         }
     }
+
     &__tags {
         font-size: 10px;
         line-height: 16px;
+
         .tag {
             display: inline-block;
             border: 1px solid rgba(172, 172, 172, .8);
             border-radius: 4px;
             padding: 0 3px;
             margin-right: 5px;
+
             &:last-child {
                 margin-right: initial;
             }
@@ -263,17 +268,21 @@ export default {
             align-items: center;
             border-bottom: 1px solid rgba(151, 151, 151, 0.2);
             padding: 10px 0;
+
             &:last-child {
                 border-bottom: initial;
             }
+
             &__pic {
                 margin-right: 16px;
+
                 img {
                     width: 24px;
                     height: 24px;
                     border-radius: 8px;
                 }
             }
+
             &__tit {
                 flex: 1;
                 text-align: left;
@@ -282,14 +291,16 @@ export default {
                 color: #0A1629;
                 line-height: 20px;
             }
+
             &__ignore {
                 display: flex;
+                align-items: center;
             }
+
             &__msg {
                 font-size: 12px;
                 font-weight: 400;
                 color: #999999;
-                line-height: 18px;
                 margin-right: 10px;
             }
         }
@@ -299,6 +310,7 @@ export default {
 .scroll-box {
     height: 100%;
     overflow: auto;
+
     &::-webkit-scrollbar {
         display: none;
     }

+ 1 - 2
src/views/apply-state/index.vue

@@ -184,9 +184,8 @@ export default {
                         __rows_item__: formatApproveItemRow(item, THAT.formType)
                     }))
 
-                    console.log('%c record_list >>>', 'background: blue; color: #fff', list);
-
                     if (list.length < this.pagination.page_num) this.finished = true
+
                     else {
                         this.pagination.page++
                     }

+ 19 - 8
src/views/applyfor/ProductStore.vue

@@ -310,6 +310,7 @@
  *  - 商品单选
  *  - 分类选择
  */
+
 import vueBus from '@/utils/vueBus';
 import CInput from './components/CInput.vue';
 
@@ -333,6 +334,7 @@ export default {
   },
   data: () => ({
     type: "1", // 页面状态。 默认1:商品选择。 可选项2:选择分类
+    module: '', // 进入module不同时有些许差别
     radioCategory: '', // 二级分类Id
     searchVal: '', // 搜索商品?
     categoryData: [], // 分类数据
@@ -352,6 +354,11 @@ export default {
         if (query) {
           // type = 1 // 页面类型。1 => 选择商品。 2 => 选择分类
           if (query.type) this.type = query.type
+
+          // 申请的`module`
+          if (query.module) {
+            this.module = query.module
+          }
         }
 
         await this.__queryCategoay__() // initalization query categray
@@ -437,11 +444,11 @@ export default {
       }
     },
 
-    // NOTE: 选中商品进行业务
+    // NOTE: 选中商品进行业务
     handleSelectedGoods(item) {
       const { goods_stock } = item
       this.choosedStock = item
-      this.productData = [
+      let temporaryData = [
         {
           label: '规格',
           val: '',
@@ -451,13 +458,19 @@ export default {
           label: '物品数量',
           type: 'total',
           val: ''
-        },
-        {
+        }
+      ]
+
+      // 申购明细时需要物品单价
+      if (['1'].includes(this.module)) {
+        temporaryData.push({
           label: '物品单价',
           type: 'price',
           val: ''
-        }
-      ]
+        })
+      }
+
+      this.productData = temporaryData
       this.popupVisibility = true
     },
 
@@ -512,8 +525,6 @@ export default {
               second: { ...item }
             })
             break
-            // row, item,
-            // NOTE: 选中项这边
           } else continue
         }
       }

+ 38 - 0
src/views/applyfor/applyOfUser.vue

@@ -0,0 +1,38 @@
+<template>
+  <div class="apply-user-container">
+    apply user
+  </div>
+</template>
+
+
+<script>
+import { getUserList } from '@/api/approveinfo'
+
+
+export default {
+  name: 'ApplyOfUser',
+
+  data: () => ({
+    userList: [],
+  }),
+  created() {
+    this.__user_list__()
+  },
+  methods: {
+    async __user_list__() {
+      try {
+        const res = await getUserList({
+          page: 1,
+          page_num: 9999
+        })
+        if (res.code === 1) {
+          console.log('%c printlog >>>', 'background: blue; color: #fff', res.data);
+
+        }
+      } catch (error) {
+        console.log('__user_list__ error', error);
+      }
+    }
+  }
+}
+</script>

+ 1 - 5
src/views/applyfor/components/CFiles.vue

@@ -190,10 +190,6 @@ export default {
                 message: '上传中'
             })
             // NOTE: 上传前的控制
-            // console.log('before read func>>', file);
-            // if ([].includes(file.ctype)) {
-            //     console.log('before read', file);
-            // }
             return true
         },
 
@@ -201,7 +197,7 @@ export default {
         async afterRead(file, detail) {
             console.log('after read', file, detail)
             try {
-                const url = await uploadFile(file.file)
+                const { fullurl: url } = await uploadFile(file.file)
                 const { suffix } = getStaticLinkInfo(url)
                 file.name = file.file.name
                 file.type = suffix

+ 178 - 91
src/views/applyfor/components/CFlowPath.vue

@@ -1,7 +1,5 @@
 <template>
-    <layout
-        title="流程"
-    >
+    <layout title="流程">
         <div class="custom-flow-path-container">
             <!-- 审批人 -->
             <div class="rows">
@@ -15,25 +13,26 @@
                 </div>
                 <div class="right flex flex-row">
                     <div v-if="approveSelList.length" class="procesbox flex flex-row flex-row-aic">
-                        <div
-                            class="flex flex-row"
-                            v-for="(personal, idx) in approveSelList"
-                            :key="idx"
-                        >
-                            <div class="personal flex flex-col"
-                            >
+                        <div class="flex flex-row" v-for="(personal, idx) in approveSelList" :key="idx">
+                            <div class="personal flex flex-col">
                                 <div class="avatar avatar--name">
-                                    <span class="avatar__name">{{ personal.name | changeName }}</span>
+                                    <template v-if="personal.avatar">
+                                        <img class="avatar-heade" :src="personal.avatar" />
+                                    </template>
+                                    <template v-else>
+                                        <span class="avatar__name">{{ personal.name | changeName }}</span>
+                                    </template>
                                 </div>
                                 <div class="personal__name">{{ personal.name }}</div>
                             </div>
 
-                            <van-icon class="arrow" v-if="idx !== approveSelList.length - 1" :size="14" name="arrow" />
+                            <van-icon class="arrow" v-if="idx !== approveSelList.length - 1" :size="14" name="arrow"
+                                color="rgb(151, 151, 151)" />
                         </div>
                     </div>
-                    <div v-if="approveSelList.length < 3" class="empty-box" @click="handleOpenContacts">
+                    <!-- <div v-if="approveSelList.length < 3" class="empty-box" @click="handleOpenContacts">
                         <van-icon :size="20" color="#979797" name="plus" />
-                    </div>
+                    </div> -->
                 </div>
                 <div class="rows-line"></div>
             </div>
@@ -50,30 +49,72 @@
                 </div>
                 <div class="right flex flex-row">
                     <div v-if="copySelList.length" class="procesbox flex flex-row flex-row-aic">
-                        <div
-                            class="flex flex-row"
-                            v-for="(personal, idx) in copySelList"
-                            :key="idx"
-                        >
-                            <div class="personal flex flex-col"
-                            >
+                        <div class="flex flex-row" v-if="copySelList.length > 3" @click="showMoreCopy = true">
+                            <div class="personal flex flex-col">
                                 <div class="avatar avatar--name">
-                                    <span class="avatar__name">{{ personal.name | changeName }}</span>
+                                    <span class="avatar__name">
+                                        <van-icon name="friends-o" :size="24" />
+                                    </span>
                                 </div>
-                                <div class="personal__name">{{ personal.name }}</div>
+                                <div class="personal__name">查看全部</div>
                             </div>
+                            <van-icon class="arrow" :size="14" name="plus" color="rgb(151, 151, 151)" />
+                        </div>
 
-                            <van-icon class="arrow" v-if="idx !== 2" :size="14" name="arrow" />
-
+                        <div class="flex flex-row" v-for="(personal, idx) in copySelListCompu" :key="idx">
+                            <div class="personal flex flex-col">
+                                <div class="avatar avatar--name">
+                                    <template v-if="personal.avatar">
+                                        <img class="avatar-heade" :src="personal.avatar" />
+                                    </template>
+                                    <template v-else>
+                                        <span class="avatar__name">{{ personal.name | changeName }}</span>
+                                    </template>
+                                </div>
+                                <div class="personal__name">{{ personal.name }}</div>
+                            </div>
+                            <van-icon v-if="idx !== copySelListCompu.length - 1" class="arrow" :size="14" name="plus"
+                                color="rgb(151, 151, 151)" />
+                            <van-icon v-else-if="isAllowCopy == '1'" class="arrow" :size="14" name="plus"
+                                color="rgb(151, 151, 151)" />
                         </div>
                     </div>
-                    <div v-if="copySelList.length < 3" class="empty-box" @click="handleOpenContactsCopy">
+                    <div class="empty-box" v-if="isAllowCopy == '1'" @click="handleOpenContactsCopy">
                         <van-icon :size="20" color="#979797" name="plus" />
                     </div>
                 </div>
             </div>
-
         </div>
+
+        <!-- NOTE: 当抄送人过多时  展示优化 -->
+        <van-popup v-model="showMoreCopy" position="bottom" :style="{ height: '60%' }" closeable
+            close-icon-position="top-right">
+            <div class="show-more-copy-container flex flex-col">
+                <div class="header">抄送{{ copySelList.length }}人</div>
+                <div class="main">
+                    <div class="procesbox flex flex-row flex-row-aic">
+                        <div class="flex flex-row" v-for="(personal, idx) in copySelList" :key="idx">
+                            <div class="personal flex flex-col">
+                                <div class="closebox" @click="handleRemoveSignal(personal, idx)"><van-icon name="cross"
+                                        :size="14" color="#fff" /></div>
+                                <div class="avatar avatar--name">
+                                    <template v-if="personal.avatar">
+                                        <img class="avatar-heade" :src="personal.avatar" />
+                                    </template>
+                                    <template v-else>
+                                        <span class="avatar__name">{{ personal.name | changeName }}</span>
+                                    </template>
+                                </div>
+                                <div class="personal__name">{{ personal.name }}</div>
+                            </div>
+                            <van-icon class="arrow" v-if="idx !== copySelList.length - 1" :size="14" name="plus"
+                                color="rgb(151, 151, 151)" />
+                        </div>
+                    </div>
+
+                </div>
+            </div>
+        </van-popup>
     </layout>
 </template>
 
@@ -84,6 +125,7 @@
     &-container {
         padding: 10px 12px;
         background-color: @white;
+
         .rows {
             position: relative;
             display: flex;
@@ -91,7 +133,7 @@
             // align-items: center;
             justify-content: space-between;
             margin-bottom: 16px;
-            
+
             .rows-line {
                 position: absolute;
                 left: -10px;
@@ -108,6 +150,7 @@
                     font-weight: 400;
                     color: #191A1E;
                     line-height: 18px;
+
                     &::after {
                         position: absolute;
                         content: "";
@@ -121,6 +164,7 @@
 
                     }
                 }
+
                 &__desc {
                     font-size: @font-size-third;
                     font-weight: 400;
@@ -140,6 +184,7 @@
                 border-radius: 5px;
                 border: 1px solid #EEEEEF;
             }
+
             // .right {}
             &:last-child {
                 .rows-line {
@@ -147,54 +192,89 @@
                 }
             }
         }
+    }
+}
 
-        .avatar {
-            position: relative;
-            width: 31px;
-            height: 31px;
-            background: #3290C4;
+.procesbox {
+    flex-wrap: wrap;
+
+    .avatar {
+        position: relative;
+        width: 31px;
+        height: 31px;
+        background: #3290C4;
+        border-radius: 4px;
+        font-size: @font-size-third;
+
+        &--name {
+            display: flex;
+            flex-direction: row;
+            align-items: center;
+            justify-content: center;
+        }
+
+        &-heade {
+            width: 100%;
+            height: 100%;
+            vertical-align: middle;
             border-radius: 4px;
-            &--name {
-                display: flex;
-                flex-direction: row;
-                align-items: center;
-                justify-content: center;
-            }
-            &__name {
-                font-size: @font-size-third;
-                font-family: PingFangSC-Regular, PingFang SC;
-                font-weight: 400;
-                color: #FFFFFF;
-                line-height: 9px;
-            }
         }
 
-        .procesbox {
-            flex-wrap: wrap;
-            .avatar {
-                font-size: @font-size-third;
-                &__name {
-                    white-space: nowrap;
-                }
-            }
-            .personal {
-                align-items: center;
-                &__name {
-                    font-size: @font-size-third;
-                    font-family: PingFangSC-Regular, PingFang SC;
-                    font-weight: 400;
-                    color: #9A9A9A;
-                    text-align: center;
-                    line-height: 20px;
-                }
-            }
-            .arrow {
-                height: 31px;
-                line-height: 31px;
-                padding: 0 5px;
-            }
+        &__name {
+            font-size: @font-size-third;
+            font-family: PingFangSC-Regular, PingFang SC;
+            font-weight: 400;
+            color: #FFFFFF;
+            line-height: 9px;
+            white-space: nowrap;
         }
-        
+    }
+
+    .personal {
+        position: relative;
+        align-items: center;
+
+        &__name {
+            font-size: @font-size-third;
+            font-family: PingFangSC-Regular, PingFang SC;
+            font-weight: 400;
+            color: #9A9A9A;
+            text-align: center;
+            line-height: 20px;
+        }
+
+        .closebox {
+            position: absolute;
+            right: 0;
+            top: 0;
+            z-index: 9;
+            font-size: 0;
+            transform: translate(30%, -30%);
+            background-color: #b7b5b5;
+            border-radius: 1000px;
+            padding: 1px;
+        }
+    }
+
+    .arrow {
+        height: 31px;
+        line-height: 31px;
+        padding: 0 5px;
+    }
+}
+
+.show-more-copy-container {
+    .header {
+        font-size: 12px;
+        line-height: 50px;
+        padding: 0 20px;
+        color: #828282;
+    }
+
+    .main {
+        height: 0;
+        flex: 1;
+        padding: 6px 10px;
     }
 }
 </style>
@@ -210,14 +290,19 @@ export default {
         Layout
     },
     computed: {
-        approveTxt () {
-            let list = this.approvePersonal
+        approveTxt() {
+            let list = this.approveSelList
             return list.length ? `${list.length}人依次审批` : '请选择审批人'
         },
-        sendTxt () {
-            let list = this.sendTo
+        sendTxt() {
+            let list = this.copySelList
             return list.length ? `抄送${list.length}人` : '请选择抄送人'
         },
+        copySelListCompu() {
+            let arrs = [...this.copySelList]
+            if (arrs.length > 2) return arrs.slice(-2)
+            else return arrs
+        },
     },
     props: {
         approve: {
@@ -227,47 +312,49 @@ export default {
             type: Array
         },
         isAllowCopy: { // 是否允许抄送人存在变更 (0:否, 1:是)
-            validator: val => (['0', '1'].includes(val))
+            // validator: val => (['0', '1'].includes(val)),
+            type: [String, Number],
+            default: 1
         }
     },
-    data () {
+    data() {
         return {
+            showMoreCopy: false,
             approveSelList: [],
-            copySelList: [],
-
-            personalList: [],
-            personalList2: [],
-
-            approvePersonal: [],
-            sendTo: []
+            copySelList: []
         }
     },
     methods: {
 
         // 打开钉钉联系人控件。完成选审批/抄送人操作
-        async handleOpenContacts () {
+        async handleOpenContacts() {
 
             const result = await dingtalkComplexPicker({})
-            
+
             console.log(result);
         },
-        async handleOpenContactsCopy () {
+        async handleOpenContactsCopy() {
             if (this.isAllowCopy != 1) return
-            
+
             const result = await dingtalkComplexPicker({})
-            
+
             console.log(result);
         },
+        handleRemoveSignal(person, idx) {
+            this.copySelList.splice(idx, 1)
+
+            // TODO: Update copy data.
+        }
     },
     watch: {
         approve: {
-            handler (arrs) {
+            handler(arrs) {
                 if (arrs.length) this.approveSelList = [...arrs]
             },
             deep: true,
         },
         copy: {
-            handler (arrs) {
+            handler(arrs) {
                 if (arrs.length) this.copySelList = [...arrs]
             },
             deep: true

+ 104 - 64
src/views/applyfor/components/CProductStore.vue

@@ -30,14 +30,14 @@
           </div>
         </div>
         <div class="product-list__rows">
-          <!-- TODO: 数据结构未知暂不修改 -->
           <div class="prow" v-for="(item, idx) in list" :key="idx">
             <div class="prow-header flex flex-row flex-row-aic">
               <div class="prow-header__left">
                 {{ item.goods_name }}
               </div>
               <div class="prow-header__right">
-                <span class="update" @click="handleUpdateRow(item, idx)">更改</span>
+                <!-- NOTE: flag == 2 不可以修改 -->
+                <span class="update" v-show="item.flag != 2" @click="handleUpdateRow(item, idx)">更改</span>
                 <span class="remove" @click="handleRemoveRow(item, idx)">删除</span>
               </div>
             </div>
@@ -45,12 +45,12 @@
               <div class="prow-middle flex flex-row flex--row-aic" :key="idx">
                 <div class="flex flex-row flex-row-aic">
                   <div class="tags">{{ goodsStock.name }}</div>
-                  <div class="price">¥{{ goodsStock.price }}</div>
+                  <div v-show="needShowPrice" class="price">¥{{ goodsStock.price }}</div>
                 </div>
                 <div class="count">x{{ goodsStock.stock }}</div>
               </div>
             </template>
-            <div class="prow-total">
+            <div class="prow-total" v-show="needShowPrice">
               <span>¥</span>{{ item.goods_stock | sumPrice }}
             </div>
           </div>
@@ -60,14 +60,13 @@
     </template>
     <template v-else>
       <div class="product-store__empty">
-        还未添加领用物品
+        {{ showEmptyTxt }}
       </div>
     </template>
 
-
     <!-- NOTE: 弹窗提示批量导入 -->
     <van-action-sheet v-model="productStoreActionsheetVisibility" :actions="actions" cancel-text="取消"
-      close-on-click-action @cancel="onCancel" @select="handleSelectSheet">
+      close-on-click-action @select="handleSelectSheet">
       <div class="action-sheet-container" slot="description" @click="handleDownloadHelp">
         <div class="icon">
           <img src="" alt="">
@@ -77,9 +76,7 @@
       </div>
     </van-action-sheet>
 
-    <div class="tip" style="font-size: 14px;" @click="handleTips">导入提示</div>
-    <div class="tip" style="font-size: 14px;" @click="handleTest">tips</div>
-
+    <!-- NOTE: 上传的触发点 -->
     <input ref="importTemlate" :accept="excelSuffix" type="file" name="file" id="file" @change="handleInputFileChange" />
   </div>
 </template>
@@ -261,10 +258,13 @@
 
 <script>
 
+import { postImportFile, getImportTemplate } from '@/api/common';
 import { excelSuffix } from '@/utils/constant'
+import { downloadFileUseATarget } from '@/utils/util';
 import upload from '@/utils/upload';
 import vueBus from '@/utils/vueBus';
 
+
 export default {
   name: 'CProductStore',
   props: {
@@ -278,6 +278,14 @@ export default {
     }
   },
   computed: {
+    showEmptyTxt() {
+      return `还未添加${this.title}`
+    },
+
+    // NOTE: 只有采购商品时才展示价格等相关内容
+    needShowPrice() {
+      return ['1'].includes(this.type)
+    },
     showList() {
       return Boolean(this.list.length)
     },
@@ -298,8 +306,6 @@ export default {
       return title
     },
     renderInfoList() {
-      console.log('--- renderInfoList??');
-      // if (this.list.length < 2) return this.list
       if (this.showMore) return this.list
       return this.list.slice(0, 2)
     }
@@ -338,16 +344,24 @@ export default {
       if (Array.isArray(arrs) && arrs.length) this.list = [...arrs]
     },
 
-    handleTest() {
-      this.list.push({ name: 1 })
-    },
-
     // NOTE: 处理新增和修改商品
     // 更新  flag = 3。 新增 flag = 1
     handleAddOrUpdateData(data) {
-      console.log('%c add & update data >>>', 'background: blue; color: #fff', data);
-
+      if (!data) return
+      console.log('%c handle AddOrUpdate data >>>', 'background: blue; color: #fff', data);
+
+      const { flag } = data
+      if (flag === '3') { // update
+        // NOTE: 可能存在新商品无Id情况; 要兼容
+        const hasGoodsId = Boolean(data.goods_id)
+        if (!hasGoodsId) data.flag = '1'
+        let idx = this.list.findIndex(goods => hasGoodsId ? goods.goods_id === data.goods_id : goods.__id__ === data.__id__)
+        if (idx >= 0) this.list.splice(idx, 1, { ...data })
+      } else { // add
+        this.list.push({ ...data })
+      }
     },
+
     // NOTE: 商品库选择数据
     handleUpdateList(data) {
       const { customCount, goodsStock, item, GoodsPrice } = data
@@ -379,7 +393,6 @@ export default {
       } else {
         const _template_ = {
           flag: 3,
-          id: item.id,
           goods_id: item.id,
           goods_category_first: item.goods_category_first,
           goods_category_id: item.goods_category_id,
@@ -395,13 +408,10 @@ export default {
             }
           ]
         }
+        console.log('%c printlog >>>', 'background: blue; color: #fff', _template_);
         this.list = [...this.list, _template_]
       }
     },
-    onCancel() {
-      this.$toast('取消')
-      // Toast('取消');
-    },
 
     handleSelectSheet(action, idx) {
       switch (idx) {
@@ -409,7 +419,6 @@ export default {
           this.handleDownloadTemplate()
           break
         case 1:
-          // this.handleImportFile()
           this.$refs.importTemlate.click()
           break
       }
@@ -417,18 +426,30 @@ export default {
     /**
      * @description 下载文件模板
      */
-    handleDownloadTemplate() {
-      this.$toast('通过a链接下载文件')
-      // downloadFileUseATarget
+    async handleDownloadTemplate() {
+      try {
+        const formData = {
+          module: this.type
+        }
+        const result = await getImportTemplate(formData)
+        if (result.code === 1) {
+          const { url } = result.data
+          if (url) { // url 存在下载
+            downloadFileUseATarget(url)
+          } else this.$toast('请联系网络管理员')
+        }
+      } catch (error) {
+        console.log('%c handleDownloadTemplate >>>', 'background: blue; color: #fff', error);
+      }
     },
 
     // listener input:file change
-    handleInputFileChange(event) {
+    async handleInputFileChange(event) {
       let files = event.target.files
       if (files.length) {
         let file = files[0]
         console.log('%c change file >>>', 'background: blue; color: #fff', file);
-        this.handleImportFile(file)
+        await this.handleImportFile(file)
       } else {
         this.$refs.importTemlate.value = ''
       }
@@ -437,48 +458,56 @@ export default {
     // import file
     async handleImportFile(file) {
       try {
+        // update file
         const fileHref = await upload(file)
-        console.log('%c fileHref >>>', 'background: blue; color: #fff', fileHref);
-
-        // TODO: 导入模板Api
-        // const result = await postFileTemplate({
-        //   href: fileHref
-        // })
-        // if (result.code === 1) {
-        //   console.log('%c handleImportFile >>>', 'background: blue; color: #fff', result.data);
-        // }
+
+        // post import file
+        const result = await postImportFile({
+          module: this.type,
+          file: fileHref.url
+        })
+
+        if (result.code === 1) {
+          const { error_data = [], apply_goods_data = [] } = result.data
+          if (error_data.length) {
+            // error_list => { msg: String }[]
+            this.handleTipsImport(error_data, apply_goods_data)
+          } else if (apply_goods_data.length) {
+            this.list = [
+              ...this.list,
+              ...apply_goods_data
+            ]
+          }
+        }
       } catch (error) {
         console.log('%c handleImportFileError >>>', 'background: blue; color: #fff', error);
-
       }
 
     },
-    // 下载批量导入说明
+
+    // NOTE: 下载批量导入说明
+    // Useless. 功能忽略
     handleDownloadHelp() {
-      this.$toast('下载批量导入说明')
-      console.log('%c printlog >>>', 'background: blue; color: #fff',);
-      // downloadFileUseATarget
+      // util/downloadFileUseATarget
+      this.$toast('点击下载模板进行编辑上传')
     },
 
-    handleTips() {
+    // NOTE: 提醒某某商品库存不足。让用户选择是否申领/采购
+    handleTipsImport(errs, arrs) {
       this.$dialog.confirm({
-        message: `
-        1、导入的物品-学生秋季校服商品库不存在
-        2、导入的物品-老师办公用品A4纸商品库不存在
-        3、导入的物品-库存不足,缺少5件
-        `,
+        message: errs.map((item, idx) => `${idx + 1}、${item.msg}}`).join('\t\n'),
         confirmButtonText: '取消申领',
         confirmButtonColor: 'rgba(0, 122, 255, 1)',
         cancelButtonText: '按已有的库存申领'
-      }).then(res => {
-        // TODO: 取消申请
-        console.log(res);
-      }).catch(err => {
-        // TODO: 继续领取
-        console.log(err);
+      }).catch(() => {
+        this.list = [
+          ...this.list,
+          ...arrs
+        ]
       })
     },
 
+    // NOTE: 删除单项
     handleRemoveRow(item, idx) {
       let article = item.goods_name
       this.$dialog.confirm({
@@ -493,21 +522,33 @@ export default {
     },
 
 
-    // TODO: 更新领用数据时,是重新选择还是弹出弹框
-    handleUpdateRow() {
-      // this.$router.push({
-      //   name: 'ProductStore',
-      //   query
-      // })
-
+    // NOTE: 编辑Row
+    handleUpdateRow(item) {
+      this.$store.commit({
+        type: "app/ROUTE_ADD",
+        value: "Goods"
+      })
+      this.$nextTick(() => {
+        this.$router.push({
+          name: 'Goods',
+          query: {
+            flag: '3',
+            edit: JSON.stringify(item)
+          }
+        })
+      })
     },
 
     // 前往商品库列表
     handleGoPStore() {
       this.$router.push({
-        name: 'ProductStore'
+        name: 'ProductStore',
+        query: {
+          module: this.type
+        }
       })
     },
+
     // NOTE: 添加新商品
     handleAddGoods() {
       this.$store.commit({
@@ -539,7 +580,6 @@ export default {
     }
   },
   beforeDestroy() {
-    console.log('%c destory $off updateProductList >>>', 'background: blue; color: #fff',);
     vueBus.$off('updateProductList')
     vueBus.$off('changeGoods')
   },

+ 1 - 1
src/views/applyfor/components/IndexType1.vue

@@ -62,7 +62,7 @@ export default {
             id: '',
             module: 1,
             reason: '', // 申购事由
-            type: '1', // 采购类型
+            type: '', // 采购类型
             document: [], // 附件
             images: [],
             total_amount: '', // 总金额

+ 26 - 65
src/views/applyfor/components/IndexType11.vue

@@ -1,60 +1,23 @@
 <template>
     <div class="type6-container">
-        <c-select
-            title="拟稿部门"
-            :required="true"
-            v-model="department"
-        />
-
-        <c-input
-            title="文件名称"
-            :required="true"
-            v-model="reason"
-        />
-
-        <c-select
-            title="落款"
-            :required="true"
-            v-model="department_sign"
-        />
-
-        <c-input
-            title="上会情况"
-            input-type="textarea"
-            v-model="remark"
-        />
-
-        <c-files
-            ctype="files"
-            v-model="document"
-        />
-
-        <c-select
-            title="缓急程度"
-            :required="true"
-            :list="degreeList"
-            pickerValueKey="name"
-            pickerValueId="id"
-            v-model="desc"
-        />
-
-        <c-date
-            title="拟发文时间"
-            :required="true"
-            v-model="apply_date"
-        />
-
-        <c-input
-            title="文件号"
-            :required="true"
-            v-model="serial_number"
-        />
-
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-select title="拟稿部门" :required="true" v-model="department" />
+
+        <c-input title="文件名称" :required="true" v-model="reason" />
+
+        <c-select title="落款" :required="true" v-model="department_sign" />
+
+        <c-input title="上会情况" input-type="textarea" v-model="remark" />
+
+        <c-files ctype="files" v-model="document" />
+
+        <c-select title="缓急程度" :required="true" :list="degreeList" pickerValueKey="name" pickerValueId="id"
+            v-model="desc" />
+
+        <c-date title="拟发文时间" :required="true" v-model="apply_date" />
+
+        <c-input title="文件号" :required="true" v-model="serial_number" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
 
     </div>
 </template>
@@ -76,13 +39,11 @@ export default {
     mixins: [
         indexMixin
     ],
-    data () {
+    data() {
         return {
             postApi: null,
             degreeList: this.$store.state.enum.degreeList,
 
-            // TODO: 缺少拟稿部门、落款选择数据列表
-
             // formData start
             id: '',
             module: 11,
@@ -101,20 +62,20 @@ export default {
         }
     },
 
-    created () {
+    created() {
         this.getCommonFlowPathData()
         this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
     },
 
     methods: {
         // 获取编辑数据
-        handleFormatEditData (data) {
+        handleFormatEditData(data) {
             console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
         },
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -122,7 +83,7 @@ export default {
             console.log('execute handleSubmitData', formData);
             this.__post__(formData)
         },
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
                 module: this.module,
 
@@ -144,7 +105,7 @@ export default {
             if (this.id) templateObj.id = this.id
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'department': '拟稿部门',
                 'reason': '文件名称',
@@ -167,7 +128,7 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -184,7 +145,7 @@ export default {
                     */
 
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },

+ 24 - 58
src/views/applyfor/components/IndexType2.vue

@@ -1,53 +1,21 @@
 <template>
     <div class="type6-container">
-        <c-input
-            title="呈批类型"
-            :required="true"
-            v-model="type"
-        />
-
-        <c-input
-            title="发文字号"
-            :required="true"
-            v-model="word_size"
-        />
-
-        <c-select
-            title="缓急程度"
-            :required="true"
-            v-model="desc"
-            :list="degreeList"
-            pickerValueKey="name"
-            pickerValueId="id"
-        />
-
-        <c-input
-            title="印制份数"
-            input-type="number"
-            v-model="number"
-        />
-                
-        <c-input
-            title="申请标题"
-            :required="true"
-            v-model="reason"
-        />
-
-        <c-input
-            title="申请内容"
-            input-type="textarea"
-            v-model="remark"
-        />
-
-        <c-files
-            v-model="document"
-        />
-
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-input title="呈批类型" :required="true" v-model="type" />
+
+        <c-input title="发文字号" :required="true" v-model="word_size" />
+
+        <c-select title="缓急程度" :required="true" v-model="desc" :list="degreeList" pickerValueKey="name"
+            pickerValueId="id" />
+
+        <c-input title="印制份数" input-type="number" v-model="number" />
+
+        <c-input title="申请标题" :required="true" v-model="reason" />
+
+        <c-input title="申请内容" input-type="textarea" v-model="remark" />
+
+        <c-files v-model="document" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
 
     </div>
 </template>
@@ -69,13 +37,11 @@ export default {
     mixins: [
         indexMixin
     ],
-    data () {
+    data() {
         return {
             postApi: null,
             degreeList: this.$store.state.enum.degreeList,
 
-            // TODO: 缺少拟稿部门、落款选择数据列表
-
             // formData start
             id: '',
             module: 2,
@@ -93,20 +59,20 @@ export default {
         }
     },
 
-    created () {
+    created() {
         this.getCommonFlowPathData()
         this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
     },
 
     methods: {
         // 获取编辑数据
-        handleFormatEditData (data) {
+        handleFormatEditData(data) {
             console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
         },
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -114,7 +80,7 @@ export default {
             console.log('execute handleSubmitData', formData);
             this.__post__(formData)
         },
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
                 module: this.module,
                 reason: this.reason,
@@ -134,7 +100,7 @@ export default {
             if (this.id) templateObj.id = this.id
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'type': '呈批类型',
                 'word_size': '发文字号',
@@ -153,7 +119,7 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -168,7 +134,7 @@ export default {
                     })
                     */
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it2, __post__', e);
             }
         },

+ 19 - 38
src/views/applyfor/components/IndexType3.vue

@@ -3,34 +3,17 @@
 
         <!-- TODO: 关联采购审批单 -->
         <!-- 需要新增页面 -->
-        <c-select
-            title="采购审批单"
-        />
-                
-        <c-product-store
-            type="3"
-        />
-
-        <c-files
-            v-model="document"
-        />
-
-        <c-files
-            v-model="images"
-            ctype="images"
-        />
-
-        <c-input
-            title="其他补充说明"
-            input-type="textarea"
-            v-model="remark"
-        />
-
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-select title="采购审批单" />
+
+        <c-product-store type="3" />
+
+        <c-files v-model="document" />
+
+        <c-files v-model="images" ctype="images" />
+
+        <c-input title="其他补充说明" input-type="textarea" v-model="remark" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
 
     </div>
 </template>
@@ -58,13 +41,11 @@ export default {
     components: {
         CProductStore
     },
-    data () {
+    data() {
         return {
             postApi: null,
             degreeList: this.$store.state.enum.degreeList,
 
-            // TODO: 缺少拟稿部门、落款选择数据列表
-
             // formData start
             id: '',
             module: 3,
@@ -81,20 +62,20 @@ export default {
         }
     },
 
-    created () {
+    created() {
         this.getCommonFlowPathData()
         this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
     },
 
     methods: {
         // 获取编辑数据
-        handleFormatEditData (data) {
+        handleFormatEditData(data) {
             console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
         },
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -102,7 +83,7 @@ export default {
             console.log('execute handleSubmitData', formData);
             this.__post__(formData)
         },
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
                 module: this.module,
 
@@ -121,7 +102,7 @@ export default {
             if (this.id) templateObj.id = this.id
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'libraryInfo': '入库明细'
             }
@@ -134,7 +115,7 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -151,7 +132,7 @@ export default {
                     */
 
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },

+ 21 - 39
src/views/applyfor/components/IndexType4.vue

@@ -1,30 +1,14 @@
 <template>
     <div class="type6-container">
-        <c-input
-            title="物品用途"
-            v-model="reason"
-        />
-
-        <c-product-store
-            type="4"
-        />
-
-        <c-files
-            ctype="files"
-            v-model="document"
-        />
-
-        <c-input
-            title="其他补充说明"
-            input-type="textarea"
-            v-model="remark"
-        />
-
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-input title="物品用途" v-model="reason" />
+
+        <c-product-store type="4" />
+
+        <c-files ctype="files" v-model="document" />
+
+        <c-input title="其他补充说明" input-type="textarea" v-model="remark" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
 
     </div>
 </template>
@@ -51,13 +35,11 @@ export default {
     components: {
         CProductStore
     },
-    data () {
+    data() {
         return {
             postApi: null,
             degreeList: this.$store.state.enum.degreeList,
 
-            // TODO: 缺少拟稿部门、落款选择数据列表
-
             // formData start
             id: '',
             module: 4,
@@ -65,7 +47,7 @@ export default {
             document: [], // 附件
             remark: '', // 补充说明
 
-            infolist: '', // 明细
+            use_goods: '', // 明细
 
             approve_user: [],
             copy_user: []
@@ -73,20 +55,20 @@ export default {
         }
     },
 
-    created () {
+    created() {
         this.getCommonFlowPathData()
         this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
     },
 
     methods: {
         // 获取编辑数据
-        handleFormatEditData (data) {
+        handleFormatEditData(data) {
             console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
         },
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -94,12 +76,12 @@ export default {
             console.log('execute handleSubmitData', formData);
             this.__post__(formData)
         },
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
                 module: this.module,
                 reason: this.reason,
                 remark: this.remark,
-                infolist: this.infolist,
+                use_goods: this.use_goods,
 
                 approve_user: this.approvePeople.map(user => (user.userid || user.emplId)).join(','),
                 copy_user: this.copyPeople.map(user => (user.userid || user.emplId)).join(',')
@@ -111,12 +93,12 @@ export default {
             if (this.id) templateObj.id = this.id
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
-                'infolist': '领用明细'
+                'use_goods': '领用明细'
             }
             let requiredKey = [
-                'infolist'
+                'use_goods'
             ]
             return this.__validtor__({
                 mapTxt,
@@ -124,7 +106,7 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -141,7 +123,7 @@ export default {
                     */
 
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },

+ 25 - 64
src/views/applyfor/components/IndexType6.vue

@@ -1,64 +1,25 @@
 <template>
     <div class="type6-container">
-        <c-select
-            title="请假类型"
-            :required="true"
-            :list="askForleaveTypeList"
-            pickerValueKey="name"
-            pickerValueId="id"
-            v-model="type"
-        />
+        <c-select-imitate title="申请人" />
 
-        <c-date
-            title="请假开始时间"
-            :required="true"
-            :has-am="true"
-            v-model="start_time"
-        />
+        <c-select title="请假类型" :required="true" :list="askForleaveTypeList" pickerValueKey="name" pickerValueId="id"
+            v-model="type" />
 
-        <c-date
-            title="请假结束时间"
-            :required="true"
-            :has-am="true"
-            v-model="end_time"
-        />
+        <c-date title="请假开始时间" :required="true" :has-am="true" v-model="start_time" />
 
-        <c-input 
-            title="请假时长(时)"
-            input-type="number"
-            v-model="time"
-        />
+        <c-date title="请假结束时间" :required="true" :has-am="true" v-model="end_time" />
 
-        <c-input
-            title="原因"
-            :required="true"
-            input-type="textarea"
-            :maxlength="300"
-            v-model="reason"
-        />
+        <c-input title="请假时长(时)" input-type="number" v-model="time" />
 
-        <c-files
-            ctype="files"
-            v-model="document"
-        />
+        <c-input title="原因" :required="true" input-type="textarea" :maxlength="300" v-model="reason" />
 
-        <c-files
-            ctype="images"
-            v-model="images"
-        />
+        <c-files ctype="files" v-model="document" />
 
-        <c-input 
-            title="是否离“深”"
-            input-type="textarea"
-            placeholder="需写清目的地(到街道)、是否涉疫、出行方式及班次"
-            v-model="remark"
-        />
+        <c-files ctype="images" v-model="images" />
 
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-input title="是否离“深”" input-type="textarea" placeholder="需写清目的地(到街道)、是否涉疫、出行方式及班次" v-model="remark" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
     </div>
 </template>
 
@@ -85,7 +46,7 @@ export default {
             "timeList": "timeList"
         })
     },
-    data () {
+    data() {
         return {
             postApi: null,
 
@@ -110,7 +71,7 @@ export default {
         }
     },
 
-    created () {
+    created() {
         // NOTE: 判断是否有请假类型。 无请假类型router.replace到请假类型上
         let type = this.$route.query.asktype
         if (!type) {
@@ -121,7 +82,7 @@ export default {
     },
 
     methods: {
-        init () {
+        init() {
             this.getCommonFlowPathData()
             this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
         },
@@ -131,14 +92,14 @@ export default {
         },
 
         // 获取编辑数据
-        handleFormatEditData (data) {
+        handleFormatEditData(data) {
             console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
         },
 
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -147,7 +108,7 @@ export default {
             this.__post__(formData)
         },
 
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
                 module: this.module,
                 reason: this.reason,
@@ -174,7 +135,7 @@ export default {
 
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'type': '请假类型',
                 'start_time': '开始时间',
@@ -193,7 +154,7 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -209,13 +170,13 @@ export default {
                     })
                     */
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },
 
         // NOTE: 检查时间并且查询流程数据
-        checkTimeAndGetFlow () {
+        checkTimeAndGetFlow() {
             let start_time = this.start_time
             let end_time = this.end_time
 
@@ -242,14 +203,14 @@ export default {
     },
 
     watch: {
-        type (val, valo) {
+        type(val, valo) {
             if (val && val !== valo) this.getCommonFlowPathData()
         },
 
-        start_time () {
+        start_time() {
             this.checkTimeAndGetFlow()
         },
-        end_time () {
+        end_time() {
             this.checkTimeAndGetFlow()
         }
     }

+ 56 - 44
src/views/applyfor/components/IndexType7.vue

@@ -1,52 +1,27 @@
 <template>
     <div class="type6-container">
 
+
+        <c-select-imitate title="申请人" :value="apply_user_id_txt" @click="handleEditApplyofUser" />
+
         <div class="group-box">
             <div class="group__title">用车信息</div>
-            <c-input
-                title="出发地点"
-                :required="true"
-                v-model="reason"
-             />
-            <c-date
-                title="出发时间"
-                :required="true"
-                v-model="start_time"
-            />
+            <c-input title="出发地点" :required="true" v-model="reason" />
+            <c-date title="出发时间" :required="true" v-model="start_time" />
         </div>
 
 
         <div class="group-box m-t-10">
-            <c-input
-                title="到达地点"
-                :required="true"
-                v-model="reach_address"
-             />
-            <c-date
-                title="返回时间"
-                v-model="end_time"
-            />
-            <c-input
-                title="返回地点"
-                v-model="end_address"
-             />
+            <c-input title="到达地点" :required="true" v-model="reach_address" />
+            <c-date title="返回时间" v-model="end_time" />
+            <c-input title="返回地点" v-model="end_address" />
         </div>
 
-        <c-files
-            ctype="files"
-            v-model="document"
-        />
+        <c-files ctype="files" v-model="document" />
 
-        <c-files
-            ctype="images"
-            v-model="images"
-        />
+        <c-files ctype="images" v-model="images" />
 
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
 
     </div>
 </template>
@@ -62,17 +37,29 @@ import indexMixin from '../indexMixins'
 import { postCreateInfo } from '@/api/approveinfo'
 import { editApprove } from '@/api/approve'
 
+import { mapState } from 'vuex'
+
+import { dingtalkComplexPicker } from "@/utils/dingtalk"
+
 
 export default {
     name: 'IndexType7',
     mixins: [
         indexMixin
     ],
-    data () {
+    computed: {
+        ...mapState("user", [
+            'token',
+            'userinfo'
+        ])
+    },
+    data() {
         return {
             postApi: null,
 
             // formData start
+            apply_user_id: '',
+            apply_user_id_txt: '',
             id: '',
             module: 7,
             reason: '', // 出发地点
@@ -88,20 +75,29 @@ export default {
         }
     },
 
-    created () {
+    created() {
         this.getCommonFlowPathData()
         this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
+
+
+        console.log('%c ???? >>>', 'background: blue; color: #fff', this.token);
+
+        if (this.token) {
+            console.log('%c ----- >>>', 'background: blue; color: #fff', this.userinfo);
+            this.apply_user_id_txt = this.userinfo.name
+            this.apply_user_id = this.userinfo.userid
+        }
     },
 
     methods: {
         // 获取编辑数据
-        handleFormatEditData (data) {
+        handleFormatEditData(data) {
             console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
         },
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -109,7 +105,7 @@ export default {
             console.log('execute handleSubmitData', formData);
             this.__post__(formData)
         },
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
                 module: this.module,
                 reason: this.reason,
@@ -134,7 +130,7 @@ export default {
             // images
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'start_time': '出发时间',
                 'end_time': '返回时间',
@@ -151,7 +147,7 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -168,10 +164,26 @@ export default {
                     */
 
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },
+
+        // NOTE: 跳转申请人列表页面 进行选择申请人
+        async handleEditApplyofUser() {
+            try {
+                const result = await dingtalkComplexPicker({})
+                console.log('%c complexPicker >>>', 'background: blue; color: #fff', result);
+            } catch (error) {
+                console.log('---', error);
+            }
+            // 通过钉钉查询
+            // NOET: 通过页面查询
+            // this.$router.push({
+            //     name: 'ApplyUser',
+            //     query: {}
+            // })
+        }
     },
 }
 

+ 237 - 9
src/views/applyfor/goods-specifications.vue

@@ -1,32 +1,260 @@
 <template>
-  <div class="specifications-container">
+  <div class="specifications-container flex flex-col">
+    <div class="s-header flex flex-row flex-row-aic" v-show="goods_stock.length">
+      <span>商品规格</span>
+      <div class="icons">
+        <van-icon @click="handleRemoveAll" name="delete-o" :size="18" color="#828181" />
+        <van-icon @click="closeable = !closeable" name="setting-o" :size="closeable ? 20 : 18"
+          :color="closeable ? '#414141' : '#828181'" />
+      </div>
+    </div>
+    <div class="s-context flex flex-row" v-show="goods_stock.length">
+      <template v-for="(standar, idx) in goods_stock">
+        <van-tag :closeable="closeable" size="large" type="primary" @close="handleClose(standar, idx)"
+          @click="handleEdit(standar, idx)" :key="idx">
+          {{ standar.name }}
+        </van-tag>
+      </template>
+    </div>
+    <div class="s-btn" v-show="goods_stock.length">
+      <van-icon name="plus" :size="14" />
+      <span @click="visibilityDialog = true">追加新规格</span>
+    </div>
+
     <div class="main">
+      <!-- 内容 -->
+      <div class="standars-box" v-if="goods_stock.length">
+        <!-- NOTE: goods_stock -->
+        <div class="row" v-for="(item, idx) in goods_stock" :key="idx">
+          <div class="row__header flex flex-row flex-row-aic">
+            <span>
+              {{ item.name }}
+            </span>
+            <!-- <van-icon v-show="closeable" @click="handleClose(item, idx)" name="delete-o" :size="18" color="#b8b8b8" /> -->
+          </div>
+          <div class="row__main">
+            <!-- NOTE: 价格展示只在 申购出入库才有 -->
+            <c-input title="价格" :maxlength="9" :showWordLimit="false" input-type="number" v-model="item.price" />
+            <c-input title="数量" :maxlength="5" :showWordLimit="false" input-type="digit" v-model="item.stock" />
+          </div>
+        </div>
+
+      </div>
+
       <!-- 规格示例 -->
-      <div class="addbtn">
+      <div class="addbtn" v-else @click="visibilityDialog = true">
         <van-icon name="plus" :size="18" />
         添加规格
       </div>
-      <!-- 内容 -->
     </div>
 
+    <van-dialog v-model="visibilityDialog" title="添加/修改规格" show-cancel-button confirm-button-color="#007aff"
+      @cancel="handleCancelEvent" @confirm="handleConfirmEdit" :before-close="handleBeforeCloseDialog">
+      <van-field v-model.trim="templateValue" center input-align="center" placeholder="蓝色,165cm" />
+    </van-dialog>
+
     <!-- btn -->
-    <div class="btn-container">
-      <div class="btn-span">提交</div>
+    <div class="btn-container" v-if="goods_stock.length">
+      <div class="btn-span" @click="handleSubmitStandars">提交</div>
     </div>
   </div>
 </template>
 <script>
+import CInput from './components/CInput.vue'
+import vueBus from '@/utils/vueBus'
+
 /**
  * @description 商品规格页面
  */
 export default {
   name: 'GoodsSpeci',
+  components: {
+    CInput
+  },
   data: () => ({
-    standars: []
+    templateValue: '',
+    visibilityDialog: false,
+    closeable: false,
+    editIdx: -1,
+    goods_stock: [], // {name, price, stock}
   }),
   created() {
-    console.log('%c standars >>>', 'background: blue; color: #fff', this.$route.query.standars);
-
+    // NOTE: 携带规格更新
+    this.__init__()
   },
+  methods: {
+    __init__() {
+      // NOTE: 携带规格更新
+      const { goods_stock } = this.$route.query
+      const stocks = goods_stock ? JSON.parse(goods_stock) : []
+
+      if (stocks.length) {
+        this.goods_stock = [...stocks].reverse()
+      }
+    },
+    // Remove all standars
+    handleRemoveAll() {
+      this.$dialog.confirm({
+        message: '是否删除全部规格',
+        confirmButtonColor: '#007aff',
+      }).then(() => {
+        this.goods_stock = []
+      }).catch(() => { })
+    },
+
+    // Close signal
+    handleClose(standar, idx) {
+      this.$dialog.confirm({
+        message: `是否删除规格 ${standar.name}`,
+        confirmButtonColor: '#007aff',
+      }).then(() => {
+        this.goods_stock.splice(idx, 1)
+      }).catch(() => { })
+    },
+
+    // Edit signal
+    handleEdit(standar, idx) {
+      this.templateValue = standar
+      this.visibilityDialog = true
+      this.editIdx = idx
+    },
+
+    // Close dialog on before-close
+    handleBeforeCloseDialog(action, done) {
+      if (action === 'confirm' && !this.templateValue) return done(false)
+      const isRepeat = this.goods_stock.some(stock => stock.name === this.templateValue)
+      if (isRepeat) return done(false)
+      return done()
+    },
+
+    handleCancelEvent() {
+      this.visibilityDialog = false
+      this.templateValue = ''
+      this.editIdx = -1
+    },
+    // Confirm edit
+    handleConfirmEdit() {
+      const val = this.templateValue
+      if (!val) return this.$toast('规格名称为空')
+      const isRepeat = this.goods_stock.some(stock => stock.name === val)
+      if (isRepeat) return this.$toast('规格名称重复!')
+
+      if (this.editIdx >= 0) {
+        this.goods_stock.splice(this.editIdx, 1, {
+          ...this.goods_stock[this.editIdx],
+          name: val
+        })
+      } else {
+        this.goods_stock.unshift({
+          name: val,
+          price: '',
+          stock: '',
+        })
+      }
+      this.$nextTick(() => {
+        this.visibilityDialog = false
+        this.templateValue = ''
+        this.editIdx = -1
+      })
+    },
+
+    // submit data
+    handleSubmitStandars() {
+      const arrs = this.goods_stock
+      let isExist = false
+      // NOTE: 判断内容是否存在
+      for (let i = 0; i < arrs.length; i++) {
+        const { price, stock, name } = arrs[i];
+        if (!price || !stock) {
+          isExist = true
+          this.$toast(`规则${name}的${!price ? '价格' : '数量'}为空,请填写`)
+          break
+        }
+      }
+
+      if (isExist) return
+
+      vueBus.$emit('listenStrandarsEvent', [...arrs].reverse())
+
+      this.$nextTick(() => {
+        this.$router.go(-1)
+      })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.specifications-container {
+  height: 100vh;
+  justify-content: space-between;
+
+  .s-header {
+    justify-content: space-between;
+    background-color: #fff;
+    font-size: 18px;
+    padding: 10px;
+    border-bottom: 1px solid #eee;
+
+    .icons {
+      letter-spacing: 8px;
+    }
+  }
+
+  .s-btn {
+    padding: 12px 0;
+    text-align: center;
+    font-size: 14px;
+    color: #3290C4;
+  }
+
+  .s-context {
+    flex-wrap: wrap;
+    gap: 12px;
+    padding: 18px 10px;
+    background-color: #fff;
+  }
+
+  .main {
+    height: 0;
+    flex: 1;
+    overflow: auto;
+
+    .addbtn {
+      width: 195px;
+      height: 42px;
+      line-height: 42px;
+      text-align: center;
+      background: #FFFFFF;
+      border-radius: 21px;
+      border: 1px solid #3290C4;
+      font-size: 16px;
+      font-weight: 500;
+      color: #3290C4;
+      margin: 80px auto;
+    }
+
+    .row {
+      &__header {
+        justify-content: space-between;
+        padding: 0 10px;
+        font-size: 14px;
+        font-family: PingFangSC, PingFang SC;
+        font-weight: 400;
+        color: #727273;
+        line-height: 32px;
+      }
+
+      &__main {
+        .layout-container {
+          border-bottom: 1px solid #eee;
+
+          &:last-child {
+            border-bottom: initial;
+          }
+        }
+      }
+    }
+  }
 }
-</script>
+</style>

+ 0 - 5
src/views/applyfor/goods-unit-price.vue

@@ -1,5 +0,0 @@
-<script>
-/**
- * @description 商品单价和数量
- */
-</script>

+ 61 - 23
src/views/applyfor/goods.vue

@@ -1,7 +1,8 @@
 <template>
   <div class="goods-container flex flex-col">
     <div class="goods__main">
-      <c-select-imitate title="商品分类" :value="goods_category_text" @click="handleClickCategory"
+      <!-- NOTE: flag === 3 时、商品分类不展示/无法获取中文枚举(只能通过接口来) -->
+      <c-select-imitate v-if="flag === '1'" title="商品分类" :value="goods_category_text" @click="handleClickCategory"
         @clear="handleClearCategory" />
 
       <c-input title="商品编号" v-model="goods_no" />
@@ -12,14 +13,11 @@
 
       <c-select-imitate title="商品规格" :value="goodsStandarsTxt" @click="handleClickStandards"
         @clear="handleClearStandards" />
-      <c-select-imitate title="单价及数量设置" :value="goodsStandarsTxt" @click="handleClickCategory"
-        @clear="handleClearStandards" />
-
     </div>
 
     <div class="goods__footer">
       <div class="btn-container">
-        <div class="btn-span">提交</div>
+        <div class="btn-span" @click="handleConfirmSubmit">{{ flag === '3' ? '修改' : '提交' }}</div>
       </div>
     </div>
   </div>
@@ -52,13 +50,13 @@
 /**
  * @description 添加商品/修改商品页
  * @date 2023/11/30
- * @param flag = edit 表示修改
+ * @param flag = 3 表示修改
  * @param goods_id = xxx 商品Id
  */
 
 import vueBus from '@/utils/vueBus';
 import CInput from './components/CInput.vue';
-import CSelect from './components/CSelect.vue';
+// import CSelect from './components/CSelect.vue';
 import CSelectImitate from './components/CSelectImitate.vue'
 
 export default {
@@ -66,34 +64,49 @@ export default {
   name_cn: '商品', // 新增或修改商品单项时存在
   components: {
     CInput,
-    CSelect,
+    // CSelect,
     CSelectImitate
   },
   computed: {
     goodsStandarsTxt() {
-      if (this.standars.length) {
-        return `共${this.standars.length}个规格`
+      if (this.goods_stock.length) {
+        return `共${this.goods_stock.length}个规格`
       } else {
         return ''
       }
-    }
+    },
   },
   data: () => ({
     flag: '1', // 默认是新增:1 修改:3
-    id: '', // 与goods_id 相同
-    goodsId: undefined, // 商品id
+    id: '', // 自定义商品的Id
+    goods_id: undefined, // 商品id
     goods_category_first: '',
     goods_category_id: '',
     goods_category_text: '',
     goods_no: '',
     goods_name: '',
     goods_brand: '',
-    standars: [], // string[]
     goods_stock: [] // object[]
   }),
   created() {
     vueBus.$on('listenCategoryEvent', this.handleCategoryData)
     vueBus.$on('listenStrandarsEvent', this.handleStandarsData)
+    const { flag } = this.$route.query
+    if (flag === '3') { // update state
+      const row = JSON.parse(this.$route.query.edit)
+      if (row) {
+        this.flag = flag
+        this.goods_id = row.goods_id
+        this.goods_category_first = row.goods_category_first
+        this.goods_category_id = row.goods_category_id
+        this.goods_no = row.goods_no
+        this.goods_name = row.goods_name
+        this.goods_brand = row.goods_brand
+        this.goods_stock = row.goods_stock
+        if (row.__id__) this.id = row.__id__ // 自定义添加商品才有
+      }
+    }
+
   },
   methods: {
     handleClickCategory() {
@@ -120,30 +133,55 @@ export default {
       this.$router.push({
         name: 'GoodsSpeci',
         query: {
-          standars: this.standars.join(',')
+          // standars: this.standars.join(','),
+          goods_stock: JSON.stringify(this.goods_stock)
         }
       })
     },
     handleClearStandards() {
-      this.standars = []
+      // this.standars = []
+      this.goods_stock = []
     },
+
     // NOTE: 更新规格数据
-    handleStandarsData(data) {
-      this.standars = data.value
+    handleStandarsData(arrs) {
+      console.log('%c ???? >>>', 'background: blue; color: #fff', arrs);
+
+      // this.standars = arrs
+      this.goods_stock = [...arrs]
     },
 
-    handleClickUnit() {
-      this.$router.push({
-        name: 'GoodsUnit',
-        query: {
-          standars: this.standars.join(',')
+    // 确认提交
+    handleConfirmSubmit() {
+
+      const temporary = {
+        flag: this.flag,
+        goods_category_first: this.goods_category_first,
+        goods_category_id: this.goods_category_id,
+        goods_no: this.goods_no,
+        goods_name: this.goods_name,
+        goods_brand: this.goods_brand,
+        goods_stock: this.goods_stock
+      }
+
+      if (this.flag === '3') { // update online goods
+        if (this.goods_id) { // 线上商品
+          temporary.goods_id = this.goods_id
+        } else if (this.id) { // 新增商品-修改
+          temporary['__id__'] = this.id
         }
+      } else temporary['__id__'] = Date.now()
+
+      vueBus.$emit('changeGoods', temporary)
+      this.$nextTick(() => {
+        this.$router.go(-1)
       })
     }
 
   },
   beforeDestroy() {
     vueBus.$off('listenCategoryEvent')
+    vueBus.$off('listenStrandarsEvent')
   }
 }
 </script>

+ 3 - 1
src/views/applyfor/js/IndexComponentsMixins.js

@@ -7,6 +7,7 @@ import CFiles from '../components/CFiles.vue';
 import CFlowPath from '../components/CFlowPath.vue';
 import CDate from '../components/CDate.vue';
 import CSwitch from '../components/CSwitch.vue'
+import CSelectImitate from '../components/CSelectImitate.vue'
 
 export default {
     components: {
@@ -15,6 +16,7 @@ export default {
         CFiles,
         CFlowPath,
         CDate,
-        CSwitch
+        CSwitch,
+        CSelectImitate
     }
 }