3 次代码提交 ccded50e5f ... 6fa935e8c4

作者 SHA1 备注 提交日期
  xutongzee 6fa935e8c4 part code yestday 1 年之前
  xutongzee 72185c8d2a update part code 1 年之前
  xutongzee b390435483 note suffix 1 年之前

+ 48 - 25
TODO.md

@@ -1,39 +1,62 @@
 # 钉钉办公系统 - 待办事项
 
-## 前端TODO
-* [x] 上传文件/图片等模块
-* [x] 下载文件通过链接下载 (等待测试)
+## 前端 TODO
 
-* [ ] 路由标题配置。 通过dingtalk Set title 
+- [x] 上传文件/图片等模块
+- [x] 下载文件通过链接下载 (等待测试)
 
-* [ ] 抄送人超过三个时显示状态需要更新
+- [ ] 路由标题配置。 通过 dingtalk Set title
 
-* [ ] 我的出差-详情页面缺少 发起人字段
+- [ ] 抄送人超过三个时显示状态需要更新
 
-* [ ] 商品规格页面
-* [ ] 商品单价页面
+- [ ] 我的出差-详情页面缺少 发起人字段
+
+- [ ] 商品规格页面
+
+- [ ] 商品单价页面
 
 ### 缺少明细的页面
-* 申购1
-* 入库3
-* 领用(已添加 4
+
+- 申购 1
+- 入库 3
+- 领用(已添加 4
 
 ## About Ui
 
-* [ ] 个人中心`tag`Icons需要补充
-* [ ] 个人中心头像和签名图片是走钉钉功能。 尚未自测
-* [ ] product-store icon
-* [ ] 审批详情 底部的 各种功能ICONS 需要设计师给予
-* [ ] 审批详情 顶部 ICON需要 设计切图
+- [ ] 个人中心`tag`Icons 需要补充
+- [ ] 个人中心头像和签名图片是走钉钉功能。 尚未自测
+- [ ] product-store icon
+- [ ] 审批详情 底部的 各种功能 ICONS 需要设计师给予
+- [ ] 审批详情 顶部 ICON 需要 设计切图
 
 ## RearEnd Bugs
 
-* [x] 我的出差-详情页面 流程中缺少发起人数据
-* [ ] 个人中心 编辑接口 - 更新失败
-* [ ] 个人中心`user_info`接口缺少学校名称字段
-* [ ] 提交申请流程中 - 各个模块审核人员始终为空
-* [ ] 批量导入接口[导入excel文件]缺失, 需要下载相对应的excel模板文件接口
-* [ ] 商品库接口。
-* [ ] 商品库分类接口(2级) (3级-带产品)
-* [ ] 根据商品id查询详情的接口
-* [ ] 商品库搜索商品接口
+- [ ] 批量导入接口[导入 excel 文件]缺失, 需要下载相对应的 excel 模板文件接口
+- [ ] 商品库接口。
+- [ ] 商品库分类接口(2 级) (3 级-带产品)
+- [ ] 根据商品 id 查询详情的接口
+- [ ] 商品库搜索商品接口
+
+-- 2023/12/12 --
+
+- [ ] 分类接口需要根据字段 展示全部分类数据或者 展示有商品的数据
+- [ ] 分类规格数据
+
+## Warning
+
+- [ ] 申请详情中的 发起人流程 状态是否需要?
+
+# 今日完成
+
+- 更新个人接口接口字段。
+
+## 流程
+
+- [ ] 合同呈批 type = 9
+
+- [ ] 维修流程 type = 8
+  - [x] 报表填写流程
+  - [x] 渲染展示字段
+  - [x] 回填表单
+  - [x] 审核小功能
+  - [x] 审核人员修改可以

+ 24 - 5
src/App.vue

@@ -1,6 +1,25 @@
 <template>
   <div id="app">
-    <router-view />
+    <!-- <router-view v-slot="{ Component }">
+      <keep-alive :includes="['Applyfor']">
+        <component :is="Component" />
+      </keep-alive>
+    </router-view> -->
+
+    <!-- <keep-alive :includes="['Applyfor']">
+      <router-view></router-view>
+    </keep-alive> -->
+
+    <keep-alive>
+      <router-view v-if="$route.meta.keepAlive">
+        <!-- 这里是会被缓存的视图组件,比如 Home! -->
+      </router-view>
+    </keep-alive>
+
+    <router-view v-if="!$route.meta.keepAlive">
+      <!-- 这里是不被缓存的视图组件,比如 Edit! -->
+    </router-view>
+
     <!-- <nav-bar v-show="!isShowtabbar"></nav-bar> -->
     <tab-bar v-show="isShowtabbar"></tab-bar>
   </div>
@@ -13,7 +32,6 @@ import TabBar from '@/components/TabBar'
 
 import { platform } from '@/utils/dingtalk.js'
 
-
 export default {
   components: {
     TabBar,
@@ -45,8 +63,9 @@ export default {
       tabbarActive: 0,
     };
   },
+
   computed: {
-    isShowtabbar () {
+    isShowtabbar() {
       const { path } = this.$route
       return this.allowPath.includes(path)
     }
@@ -66,8 +85,8 @@ export default {
         this.$store.dispatch('user/login')
       }
 
-      
-    } catch (e) {} /* eslint-disable-line */
+
+    } catch (e) { } /* eslint-disable-line */
 
   }
 }

+ 18 - 0
src/api/goods.js

@@ -0,0 +1,18 @@
+/**
+ * @description 商品类接口
+ */
+import request from '@/utils/request'
+
+// 获取商品列表
+// data = { category_id: '' }
+export const list = data => (request({
+  method: "POST",
+  url: "goods/get_list",
+  data
+}))
+
+// 获取商品分类
+export const category = () => (request({
+  method: "POST",
+  url: "goodscategory/get_list"
+}))

+ 17 - 22
src/components/TabBar/index.vue

@@ -1,18 +1,13 @@
 <template>
     <van-tabbar :value="tabbarActive" @change="handleTabbarChange" route>
-            <van-tabbar-item
-                v-for="(item, idx) in tabbarList"
-                :key="idx"
-                :to="item.to"
-                replace
-            >
+        <van-tabbar-item v-for="(item, idx) in tabbarList" :key="idx" :to="item.to" replace>
             <span>{{ item.title }}</span>
             <template #icon="props">
                 <img v-if="props.active" :src="item.iconSel" />
                 <img v-else :src="item.icon" />
             </template>
-            </van-tabbar-item>
-        </van-tabbar>
+        </van-tabbar-item>
+    </van-tabbar>
 </template>
 
 <script>
@@ -22,33 +17,33 @@ export default {
     computed: {
         ...mapGetters(['tabbarIdx'])
     },
-    data () {
+    data() {
         return {
             tabbarActive: this.tabbarIdx,
             tabbarList: [
                 {
-                title: '首页',
-                to: '/',
-                icon: require("@/assets/icons-index.png"),
-                iconSel: require("@/assets/icons-index-sel.png"),
+                    title: '首页',
+                    to: '/',
+                    icon: require("@/assets/icons-index.png"),
+                    iconSel: require("@/assets/icons-index-sel.png"),
                 },
                 {
-                title: '审批',
-                to: '/approve',
-                icon: require("@/assets/icons-approve.png"),
-                iconSel: require("@/assets/icons-approve-sel.png"),
+                    title: '审批',
+                    to: '/approve',
+                    icon: require("@/assets/icons-approve.png"),
+                    iconSel: require("@/assets/icons-approve-sel.png"),
                 },
                 {
-                title: '我的',
-                to: '/my',
-                icon: require("@/assets/icons-my.png"),
-                iconSel: require("@/assets/icons-my-sel.png"),
+                    title: '我的',
+                    to: '/my',
+                    icon: require("@/assets/icons-my.png"),
+                    iconSel: require("@/assets/icons-my-sel.png"),
                 },
             ]
         }
     },
     methods: {
-        handleTabbarChange (index) {
+        handleTabbarChange(index) {
             this.tabbarActive = index
             this.$store.commit({
                 type: 'app/SET_TABBAR',

+ 9 - 1
src/router/index.js

@@ -25,6 +25,9 @@ const routes = [
   {
     path: '/applyfor',
     name: 'Applyfor',
+    meta: {
+      keepAlive: true
+    },
     component: () => import(/* webpackChunkName: "index" */ '../views/applyfor/index.vue')
   },
 
@@ -34,7 +37,6 @@ const routes = [
     name: 'PeersOutForm',
     component: () => import(/* webpackChunkName: "index" */ '../views/applyfor/peersOutForm.vue')
   },
-
   {
     path: '/applyfor/type6-before',
     name: 'AskForLeave',
@@ -131,6 +133,12 @@ const router = new VueRouter({
 })
 
 router.beforeEach((to, from, next) => {
+  // TODO: 如果去往的页面不属于applyfor就可以重新恢复他的 keep-alive
+  if (!to.path.includes('applyfor')) {
+    console.log('%c ==============执行 >>>', 'background: blue; color: #fff', routes[1]);
+    routes[1].meta.keepAlive = true
+  }
+  
   // console.log('>>>>> beforeEach >>>>>');
   // console.log('to', to);
   // console.log('form', from);

+ 15 - 4
src/store/modules/app.js

@@ -1,13 +1,24 @@
 const state = {
-    tabbarIdx: 0
+    tabbarIdx: 0,
+    catchRoutes: [],
 }
 
-
 const mutations = {
-    SET_TABBAR (state, poylad) {
-        state.tabbarIdx = poylad.tabbarIdx
+    SET_TABBAR (state, payload) {
+        state.tabbarIdx = payload.tabbarIdx
         // window.localStorage.setItem('tabbarIdx', poylad.tabbarIdx)
+    },
+
+    ROUTE_ADD (state, payload){
+        state.catchRoutes.push(payload.value)
+    },
+    ROUTE_REMOVE (state, payload){
+        state.catchRoutes = state.catchRoutes.filter(route => route !== payload.value)
+    },
+    ROUTE_CLEAN (state) {
+        state.catchRoutes = []
     }
+
 }
 
 export default {

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

@@ -61,6 +61,8 @@ const getters = {
     getModuleText: state => id => getKeyToTxt(state.moduleList, id),
     // NOTE: 获取缓急程度枚举
     getDegreeText: state => id => getKeyToTxt(state.degreeList, id),
+    // NOTE: 获取维修分类
+    getMaintainText: state => id => getKeyToTxt(state.maintainTypeList, id),
 }
 
 const mutations = {

+ 5 - 4
src/store/modules/user.js

@@ -7,7 +7,7 @@ const signatureStateEnum = ['待审核', '已通过', '已驳回']
 
 const state = {
     name: '',
-    schoolName: '深圳市第二特殊教育学校', // FIXME: 后端尚未提供
+    schoolName: '深圳市第二特殊教育学校',
     mobile: '',
     userinfo: {},
     signatureStateText: '',  // 个签
@@ -22,8 +22,8 @@ const getters = {
     },
     getDepartments (state) {
         let userinfo = state.userinfo
-        if (!userinfo.department) return ''
-        return userinfo.department.split(',').join('、')
+        if (!userinfo.department_list) return ''
+        return userinfo.department_list.map(item => item.name).join('、')
     },
 
     // NOTE: 获取组织成员信息
@@ -47,10 +47,11 @@ const getters = {
 
 const mutations = {
     UPDATE_USER_DATA: (state, payload) => {
-        const { mobile, name } = payload.data
+        const { mobile, name, subject } = payload.data
         state.userinfo = payload.data
         state.mobile = mobile
         state.name = name
+        state.schoolName = subject
         state.signatureStateText = signatureStateEnum[payload.data.signature_status] || ''
     },
     // 更新用户Token

+ 60 - 0
src/utils/applyfor-item.js

@@ -0,0 +1,60 @@
+/**
+ * @description 设置审核Row的数据内容等
+ */
+
+import store from "@/store"
+// const degree2Txt = store.getters['enum/getDegreeText']
+const maintainTypeList = store.getters['enum/getMaintainText']
+
+function getModule8(data) {
+  const { order_no, department_data, module_info} = data
+  return [
+    {
+      title: '审批编号',
+      value: order_no
+    },
+    {
+      title: '所在部门',
+      value: department_data.map(department => (department.name)).join(',')
+    },
+    {
+      title: '申请日期',
+      value: data.create_at
+    },
+    {
+      title: '维修分类',
+      value: maintainTypeList(module_info.type),
+    },
+    {
+      title: '维修地点',
+      value: module_info.reason,
+    },
+
+    {
+      title: '维修内容',
+      value: module_info.desc,
+    },
+    module_info.images_text.length ? {
+      type: 'images',
+      title: '图片',
+      value: module_info.images_text.map(img => ({
+        url: img
+      }))
+    } : undefined,
+  ]
+}
+
+export const formatApplyforRows = (data) => {
+  let type = data.module
+  if (typeof type !== 'number') type = Number(type)
+  let arrs = []
+
+  switch (type) {
+    case 8:
+      arrs = getModule8(data)
+      break
+  }
+  
+  // NOTE: 过滤为undefined字段
+  return arrs.filter(item => (item))
+}

+ 3 - 0
src/utils/approve-item.js

@@ -7,7 +7,10 @@ import store from "@/store"
 const degree2Txt = store.getters['enum/getDegreeText']
 
 export function formatApproveItemRow(data, type) {
+    if (typeof type !== 'number') type = Number(type)
+    
     let arrs = []
+
     switch (type) {
         case 1:
             arrs = [

+ 3 - 3
src/utils/constant.js

@@ -13,7 +13,7 @@ export const phoneRegexp = /^1[0-9]{10}$/i
 export const excelSuffix = [
   '.xlsx',
   '.xls',
-  '.xlsm',
-  '.xlsb',
-  '.csv',
+  // '.xlsm',
+  // '.xlsb',
+  // '.csv',
 ]

+ 4 - 2
src/utils/import-vant.js

@@ -23,11 +23,13 @@ import {
     List,
     Dialog,
     ImagePreview,
-    Checkbox
+    Checkbox,
+    Radio,
+    RadioGroup
 } 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(Uploader).use(Calendar).use(DatetimePicker).use(ActionSheet).use(Switch).use(List).use(Dialog).use(Checkbox).use(Radio).use(RadioGroup)
 
 
 Vue.use(ImagePreview)

+ 100 - 151
src/views/Approve.vue

@@ -1,146 +1,66 @@
 <template>
   <div class="approve-container flex flex-col">
-    <van-tabs v-model="tabVal"
-      :before-change="handleTabBeforeChangeEvnet"
-    >
-      <van-tab
-        v-for="(tab, idx) in tabs"
-        :key="idx"
-        :title="tab.title"
-        :name="tab.name"
-        color="#000"
-        />
+    <van-tabs v-model="tabVal" :before-change="handleTabBeforeChangeEvnet">
+      <van-tab v-for="(tab, idx) in tabs" :key="idx" :title="tab.title" :name="tab.name" color="#000" />
     </van-tabs>
     <div class="filter-container p-h-12 flex flex-row flex-row-aic">
-      <van-field
-        v-model="searchVal"
-        clearable
-        placeholder="搜索"
-        left-icon="search"
-        :disabled="true"
-        :readonly="true"
-        @click="handleClickSearchBox"
-        />
-      <div class="filterbox flex flex-row flex-0shrink"
-        @click="() => popupVisibility = true"
-      >
-        <van-icon
-          name="filter-o"
-          size="20"
-        />
+      <van-field v-model="searchVal" clearable placeholder="搜索" left-icon="search" :disabled="true" :readonly="true"
+        @click="handleClickSearchBox" />
+      <div class="filterbox flex flex-row flex-0shrink" @click="() => popupVisibility = true">
+        <van-icon name="filter-o" size="20" />
         <span>筛选</span>
       </div>
     </div>
     <div class="approve-main">
-      <van-list
-        v-model="listLoading"
-        :finished="finished"
-        :finished-text="finishedText"
-        @load="onLoadData"
-      >
-        <approve-item
-          v-for="(item, idx) in tableData"
-          :key="idx"
-          approve-type="xx"
-          :title="item.__title__"
-          :time="item.apply_date"
-          :rows="item.__rows_item__"
-          :person="tabVal != 3 ? item.approve_one.user.name : ''"
-          flag="approve"
-          :flag-state="Number(tabVal)"
-          @click="handleGoInfo(item)"
-        />
+      <van-list v-model="listLoading" :finished="finished" :finished-text="finishedText" @load="onLoadData">
+        <approve-item v-for="(item, idx) in tableData" :key="idx" approve-type="xx" :title="item.__title__"
+          :time="item.apply_date" :rows="item.__rows_item__" :person="tabVal != 3 ? item.approve_one.user.name : ''"
+          flag="approve" :flag-state="Number(tabVal)" @click="handleGoInfo(item)" />
       </van-list>
-
-      <my-empty
-          v-show="showEmpty"
-          tip="暂无数据"
-      />
-
-      <!-- useless. -->
-      <!-- <div class="btnbox" @click="goexamine">jumptoexamine-pass</div>
-      <div class="btnbox" @click="goexamine2">jumptoexamine-refuse</div>
-      <div class="btnbox" @click="goDetail">goDetail</div> -->
-
-      <!-- <my-empty tip="暂无待处理的" /> -->
+      <my-empty v-show="showEmpty" tip="暂无数据" />
     </div>
 
     <!-- 弹窗 全部筛选 -->
-    <van-popup
-      class="popupxx"
-      v-model="popupVisibility"
-      position="bottom"
-      :style="{ height: '90%' }"
-      closeable
-      close-icon-position="top-left"
-      @click-close-icon="handleClosePopup"
-    >
+    <van-popup class="popupxx" v-model="popupVisibility" position="bottom" :style="{ height: '90%' }" closeable
+      close-icon-position="top-left" @click-close-icon="handleClosePopup">
       <div>
         <div class="popup__title">全部筛选</div>
-          <div class="popup__typebox">
-            <div class="popup__typebox__header">
-              <span>全部类型</span>
-            </div>
-            <div class="popup__typebox__list">
-              <span
-                v-for="(type, idx) in types"
-                :key="idx"
-                class="item"
-                :class="[
-                  'item',
-                  type.id === typeVal ? 'item--selected' : ''
-                ]"
-                @click="handleTouchThatType($event, type)"
-                >
-                {{ type.name }}
-              </span>
-            </div>
+        <div class="popup__typebox">
+          <div class="popup__typebox__header">
+            <span>全部类型</span>
+          </div>
+          <div class="popup__typebox__list">
+            <span v-for="(type, idx) in types" :key="idx" class="item" :class="[
+              'item',
+              type.id === typeVal ? 'item--selected' : ''
+            ]" @click="handleTouchThatType($event, type)">
+              {{ type.name }}
+            </span>
+          </div>
+        </div>
+        <div class="popup__rangetime">
+          <div class="popup__typebox__header">
+            <span>申请时间</span>
           </div>
-          <div class="popup__rangetime">
-            <div class="popup__typebox__header">
-              <span>申请时间</span>
-            </div>
-            <div class="popup__rangetime__main flex flex-row flex-row-aic">
-              <van-field
-                :value="timeStart"
-                :disabled="true"
-                clearable
-                placeholder="开始时间"
-                :center="true"
-                @click-input="handleClickTimeStart"
-              />
-              <span class="horization"></span>
-              
-              <van-field
-                :value="timeEnd"
-                :disabled="true"
-                clearable
-                placeholder="结束时间"
-                :center="true"
-                @click-input="handleClickTimeEnd"
-              />
-            </div>
+          <div class="popup__rangetime__main flex flex-row flex-row-aic">
+            <van-field :value="timeStart" :disabled="true" clearable placeholder="开始时间" :center="true"
+              @click-input="handleClickTimeStart" />
+            <span class="horization"></span>
+
+            <van-field :value="timeEnd" :disabled="true" clearable placeholder="结束时间" :center="true"
+              @click-input="handleClickTimeEnd" />
           </div>
+        </div>
       </div>
 
       <div class="btn-popup" @click="handleSubmitFilter">
         <span>提交</span>
       </div>
 
-      <ChooseTime
-        ref="chooseTimeRef"
-        v-model="timeStart"
-        :min-date="minDate"
-        :max-date="maxDate"
-      />
-
-      <ChooseTime
-        ref="chooseTimeRef2"
-        v-model="timeEnd"
-        :min-date="minDate"
-        :max-date="maxDate"
-      />
-        
+      <ChooseTime ref="chooseTimeRef" v-model="timeStart" :min-date="minDate" :max-date="maxDate" />
+
+      <ChooseTime ref="chooseTimeRef2" v-model="timeEnd" :min-date="minDate" :max-date="maxDate" />
+
     </van-popup>
   </div>
 </template>
@@ -164,18 +84,18 @@ export default {
     ...mapState('enum', {
       types: state => state.moduleList
     }),
-    rendeTitleCom () {
+    rendeTitleCom() {
       let t = this.formType
       let welcomeTxt = `${store.getters.name}提交的`
       switch (t) {
-          case 5:
-              welcomeTxt += '出差申请'
-              break
+        case 5:
+          welcomeTxt += '出差申请'
+          break
       }
       return welcomeTxt
     }
   },
-  data () {
+  data() {
     return {
       popupVisibility: false,
       example: [
@@ -228,11 +148,11 @@ export default {
       maxDate: ''
     }
   },
-  created () {
+  created() {
     this.__init__()
   },
   methods: {
-    __init__ () {
+    __init__() {
       // NOTE: 设置时间返回是前6个月 - 现在
       let now = new Date()
       now.setMonth(now.getMonth() - 7)
@@ -240,10 +160,10 @@ export default {
       let nowMax = new Date()
       this.maxDate = nowMax
     },
-    onLoadData () {
+    onLoadData() {
       this.__record_list__()
     },
-    async __record_list__ () {
+    async __record_list__() {
       try {
         const that = this
         const params = {
@@ -258,7 +178,7 @@ export default {
           let list = result.data || []
           list = list.map(item => ({
             ...item,
-            __title__: `${item.approve_info_user.name}提交的${that.$store.getters['enum/getModuleText'](item.type)}`,
+            __title__: `${item.approve_info_user.name}提交的${that.$store.getters['enum/getModuleText'](item.module)}`,
             __rows_item__: formatApproveItemRow(item, item.module)
           }))
 
@@ -276,7 +196,7 @@ export default {
         console.log('%c approve record_list error >>>', 'background: blue; color: #fff', error);
       }
     },
-    handleTabBeforeChangeEvnet (val) {
+    handleTabBeforeChangeEvnet(val) {
       this.tabVal = val
       this.showEmpty = false
       this.tableData = []
@@ -292,13 +212,13 @@ export default {
     },
 
     // NOTE: choosed type
-    handleTouchThatType (event, type) {
+    handleTouchThatType(event, type) {
       const { id } = type
       this.typeVal = id
     },
 
     // NOTE: 点击跳转搜索页
-    handleClickSearchBox () {
+    handleClickSearchBox() {
       this.$router.push({
         name: 'Search',
         query: {
@@ -310,41 +230,46 @@ export default {
     },
 
     // NOTE: 提交过滤搜索条件
-    handleSubmitFilter () {
+    handleSubmitFilter() {
       this.popupVisibility = false
       this.onLoadData()
     },
 
-    handleClosePopup () {
+    handleClosePopup() {
       this.typeVal = ''
       this.timeStart = ''
       this.timeEnd = ''
     },
 
-
-    // NOTE: 缺少module无法准确进入某一审批详情页面
-    handleGoInfo(item) {
-      console.log('%c handle Go_info  >>>', 'background: blue; color: #fff', item);
-      
+    // NOTE: 详情
+    handleGoInfo(data) {
+      this.$router.push({
+        name: 'ExamineDetail',
+        query: {
+          id: data.approve_id,
+          type: 'approve',
+          from: `approve_${this.tabVal}`
+        }
+      })
     },
 
-    handleClickTimeStart () {
+    handleClickTimeStart() {
       const THAT = this
       THAT.timeVal = THAT.timeStart
       this.$refs.chooseTimeRef.openChooseTime(date => {
-          THAT.timeStart = dayjs(date).format('YYYY-MM-DD HH:mm')
+        THAT.timeStart = dayjs(date).format('YYYY-MM-DD HH:mm')
       })
     },
 
-    handleClickTimeEnd () {
+    handleClickTimeEnd() {
       const THAT = this
       THAT.timeVal = THAT.timeEnd
       this.$refs.chooseTimeRef.openChooseTime(date => {
-          THAT.timeEnd = dayjs(date).format('YYYY-MM-DD HH:mm')
+        THAT.timeEnd = dayjs(date).format('YYYY-MM-DD HH:mm')
       })
     },
 
-    goexamine () {
+    goexamine() {
       this.$router.push({
         name: 'Examine',
         query: {
@@ -352,8 +277,8 @@ export default {
         }
       })
     },
-    
-    goexamine2 () {
+
+    goexamine2() {
       this.$router.push({
         name: 'Examine',
         query: {
@@ -361,7 +286,7 @@ export default {
         }
       })
     },
-    goDetail () {
+    goDetail() {
       this.$router.push({
         name: 'ExamineDetail',
         query: {}
@@ -377,22 +302,34 @@ export default {
 .approve {
   &-container {
     height: 100%;
+
     .van-tabs {
       padding-bottom: 4px;
       border-bottom: 1px solid rgba(216, 216, 216, 1);
       background-color: white;
     }
+
     .van-tabs__line {
       background-color: #000;
     }
+
     .van-popup.van-popup--bottom {
       padding: 14px 12px;
       box-sizing: border-box;
     }
   }
+
   &-main {
     flex: 1;
     padding: 6px;
+
+    .approve-item-container {
+      margin-bottom: 10px;
+
+      &:last-child {
+        margin-bottom: initial;
+      }
+    }
   }
 }
 
@@ -400,12 +337,14 @@ export default {
   padding-top: 7px;
   padding-bottom: 7px;
   background-color: @white;
+
   .van-cell.van-field {
     background-color: rgba(238, 238, 239, 1);
     border-radius: 6px;
     padding-top: 6px;
     padding-bottom: 6px;
     position: relative;
+
     &::before {
       content: "";
       position: absolute;
@@ -417,8 +356,10 @@ export default {
       background-color: transparent;
     }
   }
+
   .filterbox {
     padding-left: 10px;
+
     span {
       font-size: @font-size-third;
       font-weight: 500;
@@ -437,6 +378,7 @@ export default {
     line-height: 22px;
     padding-bottom: 30px;
   }
+
   &__typebox {
     &__header {
       font-size: @font-size-secondery;
@@ -445,11 +387,13 @@ export default {
       line-height: 20px;
       margin-bottom: 12px;
     }
+
     &__list {
       display: grid;
       grid-template-columns: repeat(3, 33.3%);
 
       padding-bottom: 14px;
+
       span.item {
         display: inline-block;
         width: 111px;
@@ -462,26 +406,31 @@ export default {
         font-weight: 400;
         color: #191A1E;
         margin-bottom: 8px;
+
         &--selected {
           background-color: #3290C4;
           color: #fff;
-        } 
+        }
       }
     }
   }
+
   &__rangetime {
     &__main {
       justify-content: space-between;
     }
+
     .van-cell.van-field {
       width: 40%;
       background: #F6F6F6;
       border-radius: 8px;
       text-align: center;
+
       .van-field__control {
         text-align: center;
       }
     }
+
     span.horization {
       display: inline-block;
       width: 30px;
@@ -495,6 +444,7 @@ export default {
   display: flex;
   flex-direction: column;
   justify-content: space-between;
+
   .btn-popup {
     background: #3290C4;
     border-radius: 11px;
@@ -507,5 +457,4 @@ export default {
     padding: 10px 0;
   }
 }
-
 </style>

+ 39 - 64
src/views/apply-state/index.vue

@@ -1,16 +1,7 @@
 <template>
     <div class="approve-container flex flex-col">
-        <van-tabs
-            v-model="tabVal"
-            :before-change="handleTabBeforeChangeEvnet"
-            >
-            <van-tab
-                v-for="(tab, idx) in tabs"
-                :key="idx"
-                :title="tab.title"
-                :name="tab.name"
-                color="#000"
-            />
+        <van-tabs v-model="tabVal" :before-change="handleTabBeforeChangeEvnet">
+            <van-tab v-for="(tab, idx) in tabs" :key="idx" :title="tab.title" :name="tab.name" color="#000" />
         </van-tabs>
         <div class="filter-container p-h-12 flex flex-row flex-row-aic">
             <van-field v-model="searchVal" clearable placeholder="搜索" left-icon="search" :disabled="true" :readonly="true"
@@ -21,30 +12,13 @@
             </div>
         </div>
         <div class="approve-main">
-            <van-list
-                v-model="listLoading"
-                :finished="finished"
-                :finished-text="finishedText"
-                @load="onLoadData"
-            >
-                <approve-item
-                    v-for="(item, idx) in tableData"
-                    :key="idx"
-                    approve-type="xx"
-                    :title="rendeTitleCom"
-                    :time="item.apply_date"
-                    :rows="item.__rows_item__"
-                    :person="item.approve_one.user.name"
-                    flag="info"
-                    :flag-state="Number(tabVal)"
-                    @click="handleGoInfo(item)"
-                />
+            <van-list v-model="listLoading" :finished="finished" :finished-text="finishedText" @load="onLoadData">
+                <approve-item v-for="(item, idx) in tableData" :key="idx" approve-type="xx" :title="rendeTitleCom"
+                    :time="item.apply_date" :rows="item.__rows_item__" :person="item.approve_one.user.name" flag="info"
+                    :flag-state="Number(tabVal)" @click="handleGoInfo(item)" />
             </van-list>
 
-            <my-empty
-                v-show="showEmpty"
-                tip="暂无数据"
-            />
+            <my-empty v-show="showEmpty" tip="暂无数据" />
         </div>
 
         <!-- 弹窗 全部筛选 -->
@@ -68,21 +42,11 @@
                         <span>申请时间</span>
                     </div>
                     <div class="popup__rangetime__main flex flex-row flex-row-aic">
-                        <van-field
-                            v-model="timeStart"
-                            clearable
-                            placeholder="开始时间"
-                            :center="true"
-                            @click-input="handleClickTimeStart"
-                        />
+                        <van-field v-model="timeStart" clearable placeholder="开始时间" :center="true"
+                            @click-input="handleClickTimeStart" />
                         <span class="horization"></span>
-                        <van-field
-                            v-model="timeEnd"
-                            clearable
-                            placeholder="结束时间"
-                            :center="true"
-                            @click-input="handleClickTimeEnd"
-                        />
+                        <van-field v-model="timeEnd" clearable placeholder="结束时间" :center="true"
+                            @click-input="handleClickTimeEnd" />
                     </div>
                 </div>
             </div>
@@ -94,12 +58,7 @@
 
         </van-popup>
 
-        <ChooseTime
-            ref="chooseTimeRef"
-            v-model="timeVal"
-            :min-date="minDate"
-            :max-date="maxDate"
-        />
+        <ChooseTime ref="chooseTimeRef" v-model="timeVal" :min-date="minDate" :max-date="maxDate" />
     </div>
 </template>
 
@@ -121,7 +80,7 @@ export default {
         ChooseTime
     },
     computed: {
-        rendeTitleCom () {
+        rendeTitleCom() {
             let t = this.formType
             let welcomeTxt = `${store.getters.name}提交的`
             switch (t) {
@@ -196,7 +155,7 @@ export default {
         this.init()
     },
     methods: {
-        init () {
+        init() {
             // NOTE: 设置时间返回是前6个月 - 现在
             let now = new Date()
             now.setMonth(now.getMonth() - 7)
@@ -204,7 +163,7 @@ export default {
             let nowMax = new Date()
             this.maxDate = nowMax
         },
-        async __record_list__ () {
+        async __record_list__() {
             try {
                 let THAT = this
                 const params = {
@@ -224,6 +183,9 @@ export default {
                         ...item,
                         __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++
@@ -238,8 +200,8 @@ export default {
                 console.log('record list', e);
             }
         },
-        
-        onLoadData () {
+
+        onLoadData() {
             this.__record_list__()
         },
 
@@ -255,7 +217,7 @@ export default {
             return true
         },
 
-        handleClickTimeStart () {
+        handleClickTimeStart() {
             const THAT = this
             THAT.timeVal = THAT.timeStart
             this.$refs.chooseTimeRef.openChooseTime(date => {
@@ -263,7 +225,7 @@ export default {
             })
         },
 
-        handleClickTimeEnd () {
+        handleClickTimeEnd() {
             const THAT = this
             THAT.timeVal = THAT.timeEnd
             this.$refs.chooseTimeRef.openChooseTime(date => {
@@ -302,7 +264,7 @@ export default {
 
             if (endTime <= startTime) {
                 this.$toast('结束时间不可以比开始时间小')
-                return 
+                return
             }
 
             // 搜索添加时间
@@ -315,9 +277,11 @@ export default {
             this.pagination.page = 1
             this.onLoadData()
         },
-        handleGoInfo (data) {
-            // console.log('goInfo>', data);
-            if (!data) return
+
+        // NOTE: 前往审核详情页面。 
+        // BUT. 我收到的不应该存在 control address.
+        handleGoInfo(data) {
+            console.log('goInfo>', data);
             this.$router.push({
                 name: 'ExamineDetail',
                 query: {
@@ -380,8 +344,10 @@ export default {
     &-main {
         flex: 1;
         padding: 6px;
+
         .approve-item-container {
             margin-bottom: 6px;
+
             &:last-child {
                 margin-bottom: initial;
             }
@@ -434,6 +400,7 @@ export default {
         line-height: 22px;
         padding-bottom: 30px;
     }
+
     &__typebox {
         &__header {
             font-size: @font-size-secondery;
@@ -442,10 +409,12 @@ export default {
             line-height: 20px;
             margin-bottom: 12px;
         }
+
         &__list {
             flex-wrap: wrap;
             justify-content: space-between;
             padding-bottom: 14px;
+
             span {
                 display: inline-block;
                 width: 111px;
@@ -461,19 +430,23 @@ export default {
             }
         }
     }
+
     &__rangetime {
         &__main {
             justify-content: space-between;
         }
+
         .van-cell.van-field {
             width: 40%;
             background: #F6F6F6;
             border-radius: 8px;
             text-align: center;
+
             .van-field__control {
                 text-align: center;
             }
         }
+
         span.horization {
             display: inline-block;
             width: 30px;
@@ -482,10 +455,12 @@ export default {
         }
     }
 }
+
 .popupxx {
     display: flex;
     flex-direction: column;
     justify-content: space-between;
+
     .btn-popup {
         background: #3290C4;
         border-radius: 11px;

+ 251 - 183
src/views/applyfor/ProductStore.vue

@@ -2,114 +2,77 @@
   <div class="product-store-container flex flex-col">
     <div class="product-store__header">
       <div class="search-box">
-        <van-field
-          v-model="searchVal"
-          clearable
-          placeholder="搜索"
-          left-icon="search"
-          @click="handleClickSearchBox"
-        />
+        <van-field v-model="searchVal" clearable placeholder="搜索" left-icon="search" @click="handleClickSearchBox" />
       </div>
       <div class="sub-title">
         <span>商品库</span>
       </div>
     </div>
 
-
     <!-- 展示内容 -->
     <div class="product-store__main">
-      <div class="row"
-        v-for="(item, idx) in tableData"
-        :key="idx"
-      >
-        <div class="row__header row__header--b-line flex flex-row flex-row-aic">
-          <div class="row__header__content">
-            {{ item.label }}
-          </div>
-          <div class="row__header__more flex flex-row flex-row-aic" @click="handleClickRow(item, idx)">
-            <van-icon name="cluster-o" :size="26" color="#3290C4" />
-            <span class="txt">下级</span>
+      <van-radio-group v-model="radioCategory">
+        <div class="row" v-for="(item, idx) in tableData" :key="idx">
+          <div class="row__header row__header--b-line flex flex-row flex-row-aic">
+            <div class="row__header__content">
+              {{ item.name }}
+            </div>
+            <div class="row__header__more flex flex-row flex-row-aic" @click="handleClickRow(item, idx)">
+              <van-icon name="cluster-o" :size="26" color="#3290C4" />
+              <span class="txt">下级</span>
+            </div>
           </div>
-        </div>
-        <div class="row__main" v-if="item.expand">
-          <div class="row__second"
-            v-for="(second, idx2) in item.children"
-            :key="idx2"
-          >
-            <div class="row__second__header row__second__header--b-line flex flex-row flex-row-aic" @click="handleClickSecondRow(second, idx2)">
-              <div class="row__second__header__content">
-                {{ second.label }}
-              </div>
-              <div class="row__second__header__more">
-                <!-- <van-icon name="arrow-up" /> -->
-                <van-icon v-if="second.expand" name="arrow-up" :size="24" color="rgba(162, 163, 164, 1)" />
-                <van-icon v-else name="arrow-down" :size="24" color="rgba(162, 163, 164, 1)" />
+          <div class="row__main" v-if="item.expand">
+            <div class="row__second" v-for="(second, idx2) in item.childlist" :key="idx2">
+              <div class="row__second__header row__second__header--b-line flex flex-row flex-row-aic"
+                @click="type === '1' ? handleClickSecondRow(second, idx2) : null">
+                <!-- NOTE: Radio. 单选组件 -->
+                <div class="radio-box" v-if="type === '2'">
+                  <van-radio :name="second.id">{{ second.name }}</van-radio>
+                </div>
+                <div v-else class="row__second__header__content">
+                  {{ second.name }}
+                </div>
+
+                <!-- NOTE: 只存在于选择商品 -->
+                <div class="row__second__header__more" v-if="type === '1'">
+                  <van-icon v-if="second.expand" name="arrow-up" :size="24" color="rgba(162, 163, 164, 1)" />
+                  <van-icon v-else name="arrow-down" :size="24" color="rgba(162, 163, 164, 1)" />
+                </div>
               </div>
-            </div>
-            <div class="row__second__main" v-if="second.expand">
-              <div class="row__third-item flex flex-row flex-row-aic"
-                v-for="(third, idx3) in second.children"
-                :key="idx3"
-              >
-                <van-checkbox
-                  v-model="third.checked"
-                  for="c1"
-                >
-                  <span id="c1" class="content">{{ third.label }}</span>
-                </van-checkbox>
+              <div class="row__second__main" v-if="second.expand && second.childlist">
+                <div class="row__third-item flex flex-row flex-row-aic" v-for="(third, idx3) in second.childlist"
+                  :key="idx3" @click="handleSelectedGoods(third, idx3)">
+                  <span id="c1">{{ third.goods_name }}</span>
+                </div>
               </div>
             </div>
           </div>
         </div>
-      </div>
-
-      <!-- TEMPORARY: 临时 -->
-      <div @click=" popupVisibility = true">open the door</div>
+      </van-radio-group>
     </div>
 
-    <van-popup
-      class="popup flex flex-col"
-      v-model="popupVisibility"
-      position="bottom"
-      :style="{ height: '60%' }"
-      closeable
-      close-icon-position="top-right"
-    >
+    <van-popup class="popup flex flex-col" v-model="popupVisibility" position="bottom" :style="{ height: '60%' }"
+      closeable close-icon-position="top-right">
       <div class="popup__header">
-        <span class="product__title">校服</span>
-        <span class="product__inventory">库存剩余:20件</span>
+        <span class="product__title" v-if="choosedStock">{{ choosedStock.goods_name }}</span>
+
+        <span class="product__inventory">{{ leftStockComp }}</span>
       </div>
       <div class="popup__main">
-        <template
-          v-for="(item, idx) in productData"
-        >
+        <template v-for="(item, idx) in productData">
           <template v-if="item.type === 'total'">
-            <c-input
-              title="物品数量"
-              placeholder="请输入物品数量"
-              :maxlength="5"
-              :showWordLimit="false"
-              input-type="number"
-              v-model="item.val"
-              :key="idx"
-            />
+            <c-input :title="item.label" :placeholder="`请输入${item.label}`" :maxlength="5" :showWordLimit="false"
+              input-type="digit" v-model="item.val" :key="idx" />
           </template>
           <template v-else>
-            <div
-              :key="idx"
-              class="product__row"
-            >
+            <div :key="idx" class="product__row">
               <div class="product__row__header">
                 {{ item.label }}
               </div>
               <div class="product__row__main">
-                <span
-                  v-for="(type, idx) in item.list"
-                  :key="idx"
-                  :data-id="type.id"
-                  :class="{'selected': item.val == type.id}"
-                  @click="handleClickItem(item, type)"
-                >{{ type.name }}</span>
+                <span v-for="(type, idx) in item.list" :key="idx" :data-id="type.id"
+                  :class="{ 'selected': item.val == type.id }" @click="handleClickItem(item, type)">{{ type.name }}</span>
               </div>
             </div>
           </template>
@@ -126,20 +89,24 @@
 
 <style lang="less" scoped>
 @import url('@/styles/variables.less');
+
 .product-store {
   &-container {
     height: 100vh;
     justify-content: space-between;
   }
+
   &__header {
     padding: 10px 12px 0;
     background-color: @white;
+
     .search-box {
       .van-cell.van-field {
-        background: rgba(118,118,128,0.12);
+        background: rgba(118, 118, 128, 0.12);
         border-radius: 8px;
       }
     }
+
     .sub-title {
       font-size: @font-size-third;
       font-weight: 400;
@@ -148,26 +115,33 @@
       padding: 10px 0;
     }
   }
+
   &__main {
     padding: 10px 0;
     height: 0;
     flex: 1;
+
     .row {
       margin-bottom: 10px;
       background-color: @white;
+
       &__header {
         padding: 10px 12px;
         justify-content: space-between;
+
         &--b-line {
           border-bottom: 1px solid #eee;
         }
+
         &__content {
           font-size: @font-size-secondery;
         }
+
         &__more {
           font-size: 16px;
           border-left: 1px solid rgba(151, 151, 151, 0.4);
           padding: 3px 10px 3px 20px;
+
           span.txt {
             padding-left: 6px;
             color: #3290c4;
@@ -183,38 +157,52 @@
         &__header {
           padding: 10px 12px;
           justify-content: space-between;
+
           &--b-line {
             border-bottom: 1px solid #eee;
           }
+
           &__content {
             font-size: @font-size-secondery;
           }
-          &__more {
 
+          &__more {}
+
+          /deep/.van-radio__label {
+            font-size: 14px;
+          }
+
+          // .van-radio__icon--checked .van-icon
+          /deep/.van-radio__icon--checked .van-icon {
+            background-color: @main-color;
+            border-color: @main-color;
           }
         }
+
         &__main {
           padding-left: 30px;
         }
       }
+
       &__third-item {
         padding: 10px 12px;
         font-size: @font-size-third;
         border-bottom: 1px solid #eee;
+
         &:last-child {
           border-bottom-color: transparent;
         }
-        .content {
-          padding-left: 10px;
-        }
+
       }
     }
   }
 }
+
 .popup {
   justify-content: space-between;
   padding: 8px 0 0;
   box-sizing: border-box;
+
   &__header {
     margin: 0 12px;
     padding-right: 30px;
@@ -223,17 +211,24 @@
     border-bottom: 1px solid rgba(151, 151, 151, 0.3);
     font-size: @font-size-common;
   }
+
   &__main {
+    margin: 18px 0;
+    height: 0;
+    flex: 1;
     overflow: auto;
+
     .layout-container {
       padding-top: 12px;
     }
   }
+
   &__footer {
     position: relative;
     z-index: 9;
     border-top: 12px solid rgba(248, 248, 248, 1);
     box-shadow: 0 -2px 16px 1px rgba(0, 0, 0, 0.2);
+
     .btn-container {
       margin-top: initial;
     }
@@ -243,15 +238,18 @@
 .product {
   &__row {
     padding: 6px 12px 16px;
+
     &:nth-last-of-type(2) {
       border-bottom: 1px solid rgba(151, 151, 151, 0.3);
     }
   }
+
   &__title {
     font-size: 16px;
     font-weight: 500;
     color: #191A1E;
   }
+
   &__inventory {
     padding-left: 10px;
     font-size: 12px;
@@ -259,17 +257,20 @@
     color: #727273;
     vertical-align: bottom;
   }
+
   &__row {
     &__header {
       font-size: @font-size-common;
       padding: 8px 0 10px;
       color: #191A1E;
     }
+
     &__main {
       display: grid;
       grid-template-columns: repeat(2, 49%);
       column-gap: 2%;
       row-gap: 10px;
+
       span {
         display: inline-block;
         text-align: center;
@@ -281,6 +282,7 @@
         padding: 8px 0;
         transition-property: background-color, color;
         transition-duration: 0.2s;
+
         &.selected {
           background: #0a83d3;
           color: @white;
@@ -292,134 +294,200 @@
 </style>
 
 <script>
-
+/**
+ * @description 当前页面处理为多种展示格式。 
+ *  - 商品单选
+ *  - 分类选择
+ */
 import vueBus from '@/utils/vueBus';
-
 import CInput from './components/CInput.vue';
 
+import * as goodsApi from '@/api/goods'
+
 export default {
   name: "ProductStore",
   components: {
     CInput
   },
+  computed: {
+    leftStockComp() {
+      if (!this.choosedStock) return ''
+      const [{ val, list }] = this.productData
+      let currentData = list.filter(item => item.id === val)
+      if (currentData.length) {
+        let len = currentData[0].stock
+        return len > 0 ? `库存剩余:${len}件` : `暂无库存`
+      } else return ''
+    }
+  },
   data: () => ({
-    searchVal: '',
-    tableData: [
-      {
-        label: '卫生用品',
-        children: [
-          {
-            label: '服装用品',
-            children: [
-              {
-                label: '防护服'
-              },
-              {
-                label: '防护服222'
-              }
-            ]
-          },
-          {
-            label: '生活用品',
-            children: [
-              {
-                label: '鞋刷子'
-              }
-            ]
-          }
-        ]
-      },
-      {
-        label: '卫生用品2',
-        children: [
-          {
-            label: '服装用品2-1',
-            children: [
-              {
-                label: '防护服2-1-1'
-              }
-            ]
-          },
-          {
-            label: '生活用品2-2',
-            children: [
-              {
-                label: '鞋刷子2-2-1'
-              }
-            ]
-          }
-        ]
-      },
-    ],
-
+    type: "1", // 页面状态。 默认1:商品选择。 可选项2:选择分类
+    radioCategory: '', // 二级分类Id
+    searchVal: '', // 搜索商品?
+    tableData: [], // 分类数据
     // NOTE: Popup data and context data
     popupVisibility: false,
-    productData: [
-      {
-        label: '颜色',
-        val: 1,
-        list: [
-          { id: 1, name: 'black' },
-          { id: 2, name: 'white' },
-          { id: 3, name: 'yellow' },
-          { id: 4, name: 'yellow' },
-          { id: 5, name: 'blue' },
-        ]
-      },
-      {
-        label: '长度',
-        val: '',
-        list: [
-          { id: 1, name: '150cm' },
-          { id: 2, name: '160cm' },
-          { id: 3, name: '170cm' },
-          { id: 4, name: '180cm' },
-        ]
-      },
-      {
-        label: '数量',
-        type: 'total',
-        val: ''
-      }
-    ]
+    productData: [], // 弹出选择商品的数量等。
+    choosedStock: null,
   }),
+
+  created() {
+    this.__init__()
+  },
   methods: {
-    __init__ () {
-      // TODO: 调用接口
+    async __init__() {
+      try {
+        let query = this.$route.query
+        if (query) {
+          // type = 1 // 页面类型。1 => 选择商品。 2 => 选择分类
+          if (query.type) this.type = query.type
+        }
+
+        await this.__queryCategoay__() // initalization query categray
+      } catch (error) {
+        console.log('ProductStore __init__ error', error);
+      }
     },
 
-    __query_data__ () {},
+    __query_data__() { },
 
-    handleClickSearchBox(){},
+    handleClickSearchBox() { },
 
     // 点击一级
     handleClickRow(row) {
-      console.log('%c printlog >>>', 'background: blue; color: #fff', row);
-      
       row.expand = !row.expand
       this.$forceUpdate()
     },
 
     // 点击二级
-    handleClickSecondRow (row) {
-      row.expand = !row.expand
-      this.$forceUpdate()
+    async handleClickSecondRow(row) {
+      try {
+        if (!row.expand && !row.childlist) { // NOTE: 只有打开时&无子级别查询
+          const toastInstance = this.$toast({
+            type: 'loading',
+            message: '加载数据中',
+            duration: 0
+          })
+          const list = await this.__queryStoreData__(row.id)
+          row.childlist = [...list]
+
+          toastInstance.clear()
+        }
+        row.expand = !row.expand
+        this.$forceUpdate()
+      } catch (error) {
+        this.$toast(error.message)
+      }
     },
-    
+
     // 选择类型
-    handleClickItem (row, item) {
+    handleClickItem(row, item) {
       row.val = item.id
     },
 
     // 弹窗确认
-    handleConfirmInput () {
-      let isAllInput = this.productData.every(item => item.val)
-      if (!isAllInput) return this.$toast('检查选择填写情况')
-      this.$toast(this.productData.map(item => item.val).join(','))
-      vueBus.$emit('updateProductList', {
-        name: 'xiaofu'
+    handleConfirmInput() {
+      try {
+        let _list = this.productData
+        let isAllInput = _list.every(item => item.val)
+        if (!isAllInput) return this.$toast('检查填写情况')
+
+        const [choosedGoodsId, customCount, GoodsPrice] = _list.map(item => item.val)
+
+        // 选中的类别对象
+        let choosedGoodsS = _list[0].list.filter(item => item.id === choosedGoodsId)[0]
+        let ChoosedGoodsStock = 0
+        if (choosedGoodsS) {
+          ChoosedGoodsStock = choosedGoodsS.stock
+        }
+
+        // 判断输入的数量是否大于库存
+        if (customCount > ChoosedGoodsStock) {
+          return this.$toast('当前商品规格数量不足')
+        }
+
+        if (GoodsPrice <= 0) {
+          return this.$toast('当前商品价格不对')
+        }
+
+        // if (this.type === '1') {}
+        vueBus.$emit('updateProductList', {
+          item: this.choosedStock,
+          goodsStock: choosedGoodsS,
+          customCount,
+          GoodsPrice
+        })
+        this.$router.go(-1);
+      } catch (error) {
+        console.log(error);
+      }
+
+    },
+
+    // NOTE: 选中某商品进行业务
+    handleSelectedGoods(item) {
+      const { goods_stock } = item
+      this.choosedStock = item
+      this.productData = [
+        {
+          label: '规格',
+          val: '',
+          list: goods_stock
+        },
+        {
+          label: '物品数量',
+          type: 'total',
+          val: ''
+        },
+        {
+          label: '物品单价',
+          type: 'total',
+          val: ''
+        }
+      ]
+      this.popupVisibility = true
+    },
+
+    // NOTE: 查询分类数据
+    __queryCategoay__() {
+      return new Promise((resolve, reject) => {
+        goodsApi.category().then(result => {
+          if (result.code === 1) {
+            this.tableData = result.data
+            resolve()
+          } else {
+            reject()
+          }
+        }).catch(error => {
+          console.log('%c error >>>', 'background: blue; color: #fff', error);
+          reject()
+        })
+      })
+    },
+
+    // NOTE: 查询商品数据
+    // @returns [] | throw error
+    __queryStoreData__(category_id) {
+      return new Promise((resolve, reject) => {
+        goodsApi.list({
+          category_id
+        }).then(result => {
+          if (result.code === 1) {
+            resolve(result.data || [])
+          }
+        }).catch(error => {
+          reject(error)
+        })
       })
     }
+  },
+
+
+  watch: {
+    radio(val) {
+      console.log('%c radio value watch? >>>', 'background: blue; color: #fff', val);
+
+    }
   }
 
 }

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

@@ -1,28 +1,19 @@
 <template>
     <!-- NOTE: 附件和图片组件 -->
     <div class="custom-files-container">
-        <div
-            :class="[
-                'custom-files__header',
-                'flex','flex-row','flex-row-aic','flex-row-jcsp',
-                filelist.length ? 'pb6' : '',
-            ]">
+        <div :class="[
+            'custom-files__header',
+            'flex', 'flex-row', 'flex-row-aic', 'flex-row-jcsp',
+            filelist.length ? 'pb6' : '',
+        ]">
             <span class="title">{{ headerTitle }}</span>
-            <van-icon
-                color="#a2a3a4"
-                :size="20"
-                name="add-o"
-                @click="handleLaunchUploadBox"
-            />
+            <van-icon color="#a2a3a4" :size="20" name="add-o" @click="handleLaunchUploadBox" />
         </div>
 
         <!-- files show style -->
         <div class="source-listbox" v-if="isFs">
             <ul class="files-container">
-                <li class="files-row flex flex-row flex-row-aic"
-                    v-for="(file, index) in filelist"
-                    :key="index"
-                >
+                <li class="files-row flex flex-row flex-row-aic" v-for="(file, index) in filelist" :key="index">
                     <div class="icon">
                         <template v-if="['png', 'jpg', 'jpeg'].includes(file.type)">
                             <span>pic</span>
@@ -38,47 +29,34 @@
                                 <div class="size">{{ file.size }}</div>
                                 <div class="review" @click="handleReviewFiles(file)">预览</div>
                             </div>
-                            <van-icon
-                                :size="20"
-                                color="#A2A3A4"
-                                name="clear"
-                                @click="handleRemoveFile(file, index)"
-                            />
+                            <van-icon :size="20" color="#A2A3A4" name="clear" @click="handleRemoveFile(file, index)" />
                         </div>
                     </div>
                 </li>
             </ul>
         </div>
 
-        <van-uploader
-            v-show="filelist.length && !isFs"
-            ref="uploadFileRef"
-            v-model="filelist"
-            preview-size="48px"
-            :max-count="$attrs.maxCount"
-            :max-size="maxSizeComp"
-            :show-upload="false"
-            :accept="acceptHandle"
-            :preview-image="!isFs"
-            :before-read="beforeRead"
-            :after-read="afterRead"
-            @oversize="onOversize"
-        >
+        <van-uploader v-show="filelist.length && !isFs" ref="uploadFileRef" v-model="filelist" preview-size="48px"
+            :max-count="$attrs.maxCount" :max-size="maxSizeComp" :show-upload="false" :accept="acceptHandle"
+            :preview-image="!isFs" :before-read="beforeRead" :after-read="afterRead" @oversize="onOversize">
         </van-uploader>
     </div>
 </template>
 
 <style lang="less" scoped>
 @import url("@/styles/variables.less");
+
 .custom-files {
     &-container {
         padding: 9px 12px;
         background: #fff;
     }
+
     &__header {
         &.pb6 {
             padding-bottom: 6px;
         }
+
         .title {
             font-size: @font-size-secondery;
             font-weight: 400;
@@ -87,25 +65,31 @@
         }
     }
 }
+
 .source-listbox {
-     // 附件样式
-     .files {
+
+    // 附件样式
+    .files {
         &-row {
             margin-bottom: 5px;
+
             &:last-child {
                 margin-bottom: initial;
             }
+
             .icon {
                 width: 35px;
                 height: 42px;
                 background: #FFCF95;
                 margin-right: 12px;
             }
+
             &__info {
                 flex: 1;
                 width: 0;
             }
         }
+
         &-name {
             width: 88%;
             font-size: @font-size-common;
@@ -113,9 +97,11 @@
             color: #191A1E;
             line-height: 18px;
         }
+
         &-other-info {
             justify-content: space-between;
             margin-top: 4px;
+
             .size {
                 font-size: @font-size-third;
                 font-weight: 400;
@@ -123,6 +109,7 @@
                 line-height: 18px;
                 margin-right: 10px;
             }
+
             .review {
                 font-size: @font-size-third;
                 font-weight: 400;
@@ -150,35 +137,38 @@ import {
 export default {
     name: 'CFiles',
     props: {
+        value: {
+            type: Array
+        },
         ctype: {
             validator: val => ['files', 'images'].includes(val),
             default: 'files'
         }
     },
     computed: {
-        isFs () { // 是否是文件类型上传
+        isFs() { // 是否是文件类型上传
             return this.ctype === 'files'
         },
-        acceptHandle () { // 图片上传文件限制
+        acceptHandle() { // 图片上传文件限制
             return this.isFs ? "*" : "image/*"
         },
-        headerTitle () {
+        headerTitle() {
             return this.isFs ? '附件' : '图片'
         },
         // 文件大小
-        maxSizeComp () {
+        maxSizeComp() {
             let mb = 1 * 1024 * 1024;
             return this.isFs ? FileSize * mb : PicSize * mb
         }
     },
 
-    data () {
+    data() {
         return {
             toastInstance: null,
             filelist: []
         }
     },
-    
+
     methods: {
         // 启动上传组件
         handleLaunchUploadBox() {
@@ -186,7 +176,7 @@ export default {
         },
 
         // @returns Boolean {true/false}
-        beforeRead () {
+        beforeRead() {
             this.toastInstance = this.$toast.loading({
                 duration: 0,
                 message: '上传中'
@@ -200,7 +190,7 @@ export default {
         },
 
         // 自行上传文件
-        async afterRead (file, detail) {
+        async afterRead(file, detail) {
             console.log('after read', file, detail)
             try {
                 const url = await uploadFile(file.file)
@@ -218,9 +208,9 @@ export default {
                 this.toastInstance.clear()
             }
         },
-        
+
         // 超出文件大小
-        onOversize () {
+        onOversize() {
             let desc = this.isFs ? `文件超过${FileSize}MB` : `图片超过${PicSize}MB`
             this.$toast(desc)
         },
@@ -228,6 +218,7 @@ export default {
         // 预览文件
         handleReviewFiles(file) {
             // TODO: 如果是图片直接预览。 非图片其他方式预览(下载、或者插件)
+
             // NOTE: 可进行图片预览类型
             if (['png', 'jpg', 'jpeg'].includes(file.type)) {
                 ImagePreview([file.url])
@@ -235,7 +226,7 @@ export default {
                 this.$toast(file.type + '预览开发中...')
             }
         },
-        handleRemoveFile (file, index) {
+        handleRemoveFile(file, index) {
             this.filelist.splice(index, 1)
         }
     },
@@ -245,19 +236,16 @@ export default {
             handler(arrs) {
                 let hasAdd = arrs.some(image => (image.content))
                 if (hasAdd) {
-                    this.$listeners['input'] && this.$emit('input', arrs)   
+                    this.$listeners['input'] && this.$emit('input', arrs)
                 }
             }
         },
         value: {
-            handler (arrs) {
+            handler(arrs) {
                 if (Array.isArray(arrs) && arrs.length) {
-                    this.filelist = [
-                        ...arrs
-                    ]
+                    this.filelist = [...arrs]
                 }
-            },
-            immediate: true
+            }
         }
     }
 }

+ 111 - 55
src/views/applyfor/components/CProductStore.vue

@@ -7,15 +7,16 @@
       </div>
       <div class="right-content flex flex-row flex-row-aic">
         <template v-if="['1', '3'].includes(type)">
-          <span @click="handleAddGoods" >添加新商品</span>
+          <span @click="handleAddGoods">添加新商品</span>
           <span class="divider"></span>
         </template>
-        <span @click="productStoreActionsheetVisibility = true" >批量导入</span>
+        <span @click="productStoreActionsheetVisibility = true">批量导入</span>
         <span class="divider"></span>
         <span @click="handleGoPStore">商品库选择</span>
       </div>
     </div>
-    <template v-if="list.length">
+
+    <template v-if="showList">
       <div class="product-list-container">
         <div class="product-list__header flex flex-row flex-row-aic" v-show="list.length > 2">
           <div class="left">领用物品</div>
@@ -30,29 +31,27 @@
         </div>
         <div class="product-list__rows">
           <!-- TODO: 数据结构未知暂不修改 -->
-          <div class="prow"
-            v-for="(item, idx) in renderInfoList"
-            :key="idx"
-          >
+          <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">更改</span>
                 <span class="remove" @click="handleRemoveRow">删除</span>
               </div>
             </div>
-            <div class="prow-middle flex flex-row flex-row-aic">
-              <div class="tags">蓝色;165cm</div>
-              <div class="count">x40</div>
-            </div>
+            <template v-for="(goodsStock, idx) in item.goods_stock">
+              <div class="prow-middle flex flex-row flex-row-aic" :key="idx">
+                <div class="tags">{{ goodsStock.name }}</div>
+                <div class="count">x40</div>
+              </div>
+            </template>
           </div>
-  
+
         </div>
       </div>
     </template>
-
     <template v-else>
       <div class="product-store__empty">
         还未添加领用物品
@@ -61,18 +60,9 @@
 
 
     <!-- NOTE: 弹窗提示批量导入 -->
-    <van-action-sheet
-      v-model="productStoreActionsheetVisibility"
-      :actions="actions"
-      cancel-text="取消"
-      close-on-click-action
-      @cancel="onCancel"
-      @select="handleSelectSheet"
-    >
-      <div
-        class="action-sheet-container"
-        slot="description"
-        @click="handleDownloadHelp">
+    <van-action-sheet v-model="productStoreActionsheetVisibility" :actions="actions" cancel-text="取消"
+      close-on-click-action @cancel="onCancel" @select="handleSelectSheet">
+      <div class="action-sheet-container" slot="description" @click="handleDownloadHelp">
         <div class="icon">
           <img src="" alt="">
         </div>
@@ -82,20 +72,15 @@
     </van-action-sheet>
 
     <div class="tip" style="font-size: 14px;" @click="handleTips">导入提示</div>
+    <div class="tip" style="font-size: 14px;" @click="handleTest">tips</div>
 
-    <input
-      ref="importTemlate"
-      :accept="excelSuffix"
-      type="file"
-      name="file"
-      id="file"
-      @change="handleInputFileChange"
-    />
+    <input ref="importTemlate" :accept="excelSuffix" type="file" name="file" id="file" @change="handleInputFileChange" />
   </div>
 </template>
 
 <style lang="less" scoped>
 @import url('@/styles/variables.less');
+
 .product-store {
   &-container {
     margin-top: 10px;
@@ -111,21 +96,27 @@
       position: absolute;
     }
   }
+
   &__header {
     padding: 4px 12px 8px;
     justify-content: space-between;
+
     .left-title {
       font-size: @font-size-common;
       color: #727273;
+
       .required {
         color: red;
       }
     }
+
     .right-content {
       font-size: @font-size-third;
+
       span {
         color: @link-color;
       }
+
       .divider {
         display: inline-block;
         width: 1px;
@@ -135,6 +126,7 @@
       }
     }
   }
+
   &__empty {
     font-size: @font-size-secondery;
     font-weight: 400;
@@ -144,6 +136,7 @@
     background-color: @white;
   }
 }
+
 .action-sheet-container {
   .icon {
     img {
@@ -152,12 +145,14 @@
       background: #DFECFD;
     }
   }
+
   .title {
     font-size: 12px;
     font-weight: 400;
     color: #191A1E;
     line-height: 18px;
   }
+
   .sub-title {
     font-size: 12px;
     font-weight: 400;
@@ -165,53 +160,66 @@
     line-height: 18px;
   }
 }
+
 .product-list {
   &-container {
     background-color: @white;
     padding: 8px 12px;
   }
+
   &__header {
     padding: 12px 0;
     justify-content: space-between;
     border-bottom: 1px solid rgba(151, 151, 151, 0.3);
+
     .left {
       font-size: 14px;
       font-weight: 400;
       color: #191A1E;
     }
+
     .right {
       font-size: 14px;
       font-weight: 400;
       color: #3290C4;
     }
   }
+
   &__rows {
     transition: height .8s;
+
     .prow {
       padding: 12px 0 10px;
       border-bottom: 1px solid rgba(151, 151, 151, 0.3);
+
       &:last-child {
         border-bottom: initial;
       }
+
       &-header {
         padding-bottom: 6px;
         justify-content: space-between;
+
         &__left {
           font-size: @font-size-secondery;
           font-weight: 400;
           color: #191A1E;
         }
+
         &__right {
           font-size: 14px;
+
           .update {
             color: #3290C4;
           }
+
           .remove {
             margin-left: 16px;
             color: #F45642;
           }
         }
       }
+
       &-middle {
         padding: 3px 0;
         justify-content: space-between;
@@ -233,16 +241,23 @@ import vueBus from '@/utils/vueBus';
 export default {
   name: 'CProductStore',
   props: {
+    value: {
+      type: Array,
+      default: () => ([])
+    },
     type: {
       validator: t => (['1', '3', '4'].includes(t)),
       required: true
     }
   },
   computed: {
-    title () {
+    showList() {
+      return Boolean(this.list.length)
+    },
+    title() {
       let type = this.type
       let title = ''
-      switch(type) {
+      switch (type) {
         case '1':
           title = '采购明细'
           break
@@ -255,7 +270,9 @@ export default {
       }
       return title
     },
-    renderInfoList () {
+    renderInfoList() {
+      console.log('--- renderInfoList??');
+      // if (this.list.length < 2) return this.list
       if (this.showMore) return this.list
       return this.list.slice(0, 2)
     }
@@ -268,23 +285,61 @@ export default {
       { name: '下载模板', color: 'rgba(0, 122, 255, 1)' },
       { name: '导入模板', color: 'rgba(0, 122, 255, 1)' },
     ],
-    list: [1, 2, 3]
+    list: []
   }),
 
-  created () {
+  created() {
     vueBus.$on('updateProductList', this.handleUpdateList)
   },
+
+  deactivated() {
+    console.log('页面隐藏?');
+  },
+
   methods: {
+
+    handleTest() {
+      this.list.push({ name: 1 })
+    },
+    // NOTE: 商品库选择数据
     handleUpdateList(data) {
-      console.log('emit', data);
+      const { customCount, goodsStock, item, GoodsPrice } = data
+      console.log('handleUpdateList', customCount, goodsStock, item, GoodsPrice);
+
+      let isHasGoods = this.list.some(goods => goods.id === item.id)
+
+      // TODO: 优先判断是否存在该商品。不存在新增。 存在添加到商品`goos_stock`中
+      if (isHasGoods) {
+        let idx = this.list.findIndex(goods => goods.id === item.id)
+        console.log('%c query idx >>>', 'background: blue; color: #fff', idx);
+      } else {
+        const _template_ = {
+          flag: 3,
+          id: item.id,
+          goods_category_first: item.goods_category_first,
+          goods_category_id: item.goods_category_id,
+          goods_no: item.goods_no,
+          goods_name: item.goods_name,
+          goods_brand: item.goods_brand,
+          goods_stock: [
+            {
+              id: goodsStock.goods_id,
+              name: goodsStock.name,
+              price: GoodsPrice,
+              stock: customCount
+            }
+          ]
+        }
+        this.list = [...this.list, _template_]
+      }
     },
     onCancel() {
       this.$toast('取消')
       // Toast('取消');
     },
 
-    handleSelectSheet (action, idx) {
-      switch(idx) {
+    handleSelectSheet(action, idx) {
+      switch (idx) {
         case 0:
           this.handleDownloadTemplate()
           break
@@ -297,13 +352,13 @@ export default {
     /**
      * @description 下载文件模板
      */
-    handleDownloadTemplate () {
+    handleDownloadTemplate() {
       this.$toast('通过a链接下载文件')
       // downloadFileUseATarget
     },
 
     // listener input:file change
-    handleInputFileChange (event) {
+    handleInputFileChange(event) {
       let files = event.target.files
       if (files.length) {
         let file = files[0]
@@ -315,7 +370,7 @@ export default {
     },
 
     // import file
-    async handleImportFile (file) {
+    async handleImportFile(file) {
       try {
         const fileHref = await upload(file)
         console.log('%c fileHref >>>', 'background: blue; color: #fff', fileHref);
@@ -329,18 +384,18 @@ export default {
         // }
       } catch (error) {
         console.log('%c handleImportFileError >>>', 'background: blue; color: #fff', error);
-        
+
       }
 
     },
     // 下载批量导入说明
-    handleDownloadHelp () {
+    handleDownloadHelp() {
       this.$toast('下载批量导入说明')
-      console.log('%c printlog >>>', 'background: blue; color: #fff', );
+      console.log('%c printlog >>>', 'background: blue; color: #fff',);
       // downloadFileUseATarget
     },
 
-    handleTips () {
+    handleTips() {
       this.$dialog.confirm({
         message: `
         1、导入的物品-学生秋季校服商品库不存在
@@ -376,7 +431,7 @@ export default {
 
 
     // TODO: 更新领用数据时,是重新选择还是弹出弹框
-    handleUpdateRow () {
+    handleUpdateRow() {
       // this.$router.push({
       //   name: 'ProductStore',
       //   query
@@ -385,21 +440,22 @@ export default {
     },
 
     // 前往商品库列表
-    handleGoPStore () {
+    handleGoPStore() {
       this.$router.push({
         name: 'ProductStore'
       })
     },
     // NOTE: 添加新商品
-    handleAddGoods () {
+    handleAddGoods() {
       this.$toast('添加商品页面')
       this.$router.push({
         name: 'Goods'
       })
     }
   },
-  beforeDestroy () {
-    vueBus.$off('updateProductList', this.handleUpdateList)
-  }
+  beforeDestroy() {
+    console.log('%c destory $off updateProductList >>>', 'background: blue; color: #fff',);
+    vueBus.$off('updateProductList')
+  },
 }
 </script>

+ 30 - 67
src/views/applyfor/components/IndexType1.vue

@@ -1,69 +1,34 @@
 <template>
     <div class="type6-container">
-        <c-input
-            title="申请事由"
-            :required="true"
-            input-type="textarea"
-            :maxlength="800"
-            v-model="reason"
-        />
-
-        <c-select
-            title="采购类型"
-            :required="true"
-            v-model="type"
-            :list="applyTypeList"
-            pickerValueKey="name"
-            pickerValueId="id"
-        />
+        <c-input title="申请事由" :required="true" input-type="textarea" :maxlength="800" v-model="reason" />
+
+        <c-select title="采购类型" :required="true" v-model="type" :list="applyTypeList" pickerValueKey="name"
+            pickerValueId="id" />
 
         <!-- NOTE: 只有货物采购才有 采购明细 -->
         <template v-if="type == '1'">
-            <c-product-store
-                type="1"
-            />
+            <c-product-store v-model="apply_goods" type="1" />
         </template>
-                
-        <c-input
-            title="总金额(元)"
-            :required="true"
-            v-model="total_amount"
-        />
-
-        <c-date
-            title="预计申购完成日期"
-            v-model="apply_date"
-        />
-
-        <c-files
-            v-model="document"
-        />
-
-        <c-files
-            ctype="images"
-            v-model="images"
-        />
-
-        <c-select
-            title="支付方式"
-            :required="true"
-            :list="applyPayTypeList"
-            v-model="pay_type"
-            pickerValueKey="name"
-            pickerValueId="id"
-        />
-
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+
+        <c-input title="总金额(元)" :required="true" v-model="total_amount" />
+
+        <c-date title="预计申购完成日期" v-model="apply_date" />
+
+        <c-files v-model="document" />
+
+        <c-files ctype="images" v-model="images" />
+
+        <c-select title="支付方式" :required="true" :list="applyPayTypeList" v-model="pay_type" pickerValueKey="name"
+            pickerValueId="id" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
     </div>
 </template>
 
 <style lang="less" scoped></style>
 
 <script>
+
 /**
  * @description 申购申请页面
  */
@@ -74,7 +39,6 @@ import { editApprove } from '@/api/approve'
 import CProductStore from './CProductStore.vue'
 
 
-
 export default {
     name: 'IndexType1',
     mixins: [
@@ -83,7 +47,7 @@ export default {
     components: {
         CProductStore
     },
-    data () {
+    data() {
         return {
             postApi: null,
             degreeList: this.$store.state.enum.degreeList,
@@ -91,38 +55,37 @@ export default {
             applyPayTypeList: this.$store.state.enum.applyPayTypeList,
 
             // TODO: 缺少拟稿部门、落款选择数据列表
-
             // formData start
             id: '',
             module: 1,
             reason: '', // 申购事由
-            type: '', // 采购类型
+            type: '1', // 采购类型
             document: [], // 附件
             images: [],
             total_amount: '', // 总金额
             pay_type: '',  // 支付方式
             apply_date: '', // 预计申购完成日期(日期)
-
+            apply_goods: [],
             approve_user: [],
             copy_user: []
             // formData end
         }
     },
 
-    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)
@@ -131,7 +94,7 @@ export default {
             this.__post__(formData)
         },
 
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
                 module: this.module,
                 reason: this.reason,
@@ -151,8 +114,8 @@ export default {
             if (this.id) templateObj.id = this.id
             return templateObj
         },
-        
-        validate (data) {
+
+        validate(data) {
             let mapTxt = {
                 'reason': '申购事由',
                 'type': '采购类型',
@@ -174,7 +137,7 @@ export default {
             })
         },
 
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -191,7 +154,7 @@ export default {
                     */
 
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },

+ 38 - 67
src/views/applyfor/components/IndexType5.vue

@@ -4,67 +4,26 @@
             <div class="btn-span">我的出差</div>
         </div>
 
-        <c-input
-            title="填写事由"
-            :required="true"
-            v-model="reason"
-        />
+        <c-input title="填写事由" :required="true" v-model="reason" />
 
-        <peers
-            v-model="peer_user"
-        />
+        <peers v-model="peer_user" />
 
-        <c-date
-            title="出差开始时间"
-            :required="true"
-            v-model="start_time"
-        />
+        <c-date title="出差开始时间" :required="true" v-model="start_time" />
 
-        <c-date
-            title="出差结束时间"
-            :required="true"
-            v-model="end_time"
-        />
+        <c-date title="出差结束时间" :required="true" v-model="end_time" />
 
-        <c-files
-            v-model="document"
-        />
+        <c-files v-model="document" />
 
-        <c-files ctype="images"
-            v-model="images"
-        />
+        <c-files ctype="images" v-model="images" />
 
-        <c-select 
-            title="类型"
-            :required="true"
-            :list="awayArr"
-            pickerValueKey="name"
-            pickerValueId="id"
-            v-model="type"
-        />
+        <c-select title="类型" :required="true" :list="awayArr" pickerValueKey="name" pickerValueId="id" v-model="type" />
 
-        <c-switch
-            v-if="type == 1"
-            title="是否跨关内关外"
-            :required="true"
-            v-model="is_who"
-            :activeValue="1"
-            :inactiveValue="0"
-        />
+        <c-switch v-if="type == 1" title="是否跨关内关外" :required="true" v-model="is_who" :activeValue="1" :inactiveValue="0" />
 
-        <c-input
-            :title="is_who ? '预算金额' : '备注'"
-            :required="Boolean(is_who)"
-            v-model="remark"
-            input-type="textarea"
-            :placeholder="is_who ? '请输入预算金额' : '请输入往返主要方式、预算金额'"
-        />
+        <c-input :title="is_who ? '预算金额' : '备注'" :required="Boolean(is_who)" v-model="remark" input-type="textarea"
+            :placeholder="is_who ? '请输入预算金额' : '请输入往返主要方式、预算金额'" />
 
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
     </div>
 </template>
 
@@ -96,7 +55,7 @@ export default {
             postApi: null,
             formType: 5,
             awayArr: this.$store.state.enum.evectionTypeList, // 出差类型
-            
+
             // 必填字段
             requiredKey: [
                 'reason',
@@ -131,17 +90,17 @@ export default {
             // ===========================
         }
     },
-    created () {
+    created() {
         this.navigationSetting()
         this.init()
     },
     methods: {
-        init () {
+        init() {
             this.getCommonFlowPathData()
             this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
         },
         // NOTE: 格式化编辑数据
-        handleFormatEditData (data) {
+        handleFormatEditData(data) {
             console.log('%c data---- >>>', 'background: blue; color: #fff', data);
             const {
                 module_info,
@@ -173,7 +132,7 @@ export default {
         },
 
         // NOTE: 设置标题等
-        navigationSetting () {
+        navigationSetting() {
             settingNavigationTitle({
                 title: '出差申请'
             })
@@ -184,19 +143,19 @@ export default {
                 callback: this.handleNavRightBack
             })
         },
-        handleNavRightBack (result) {
+        handleNavRightBack(result) {
             console.log('result', result);
             this.$router.push({
                 name: 'ApplyState',
                 query: {
-                    type: 5
+                    type: this.module,
                 }
             })
         },
         /**
          * @description 提交数据默认函数
          */
-        handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -204,7 +163,7 @@ export default {
             console.log('execute handleSubmitData');
             this.__post__(formData)
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 // TODO: 审批人修改需要更换接口
                 const res = await this.postApi(data)
@@ -221,11 +180,11 @@ export default {
                     */
 
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'reason': '申请事由',
                 'start_time': '开始时间',
@@ -239,7 +198,7 @@ export default {
                 'end_time',
                 'reason',
             ]
-            return  this.__validtor__({
+            return this.__validtor__({
                 mapTxt,
                 requiredKey,
                 data
@@ -252,7 +211,7 @@ export default {
                 return [hasEmpty, hasKey]
             })
         },
-        __format_data__ () {
+        __format_data__() {
             let params = {
                 module: 5,
                 reason: this.reason, // 申请理由
@@ -279,7 +238,7 @@ export default {
             if (Array.isArray(images) && images.length) {
                 console.log('%c add images? >>>', 'background: blue; color: #fff', images);
                 params.images = images.map(image => image.url).join(',')
-                
+
             }
 
             let documents = this.document
@@ -291,6 +250,18 @@ export default {
             return params
         },
     },
-    
+    watch: {
+        type: {
+            handler(val, oldv) {
+                if (val && val !== oldv) {
+                    this.getCommonFlowPathData({
+                        flow_item: val
+                    })
+                }
+            },
+            immediate: true
+        }
+    }
+
 }
 </script>

+ 68 - 56
src/views/applyfor/components/IndexType8.vue

@@ -1,42 +1,22 @@
 <template>
     <div class="type6-container">
 
+        <div class="btn-container" @click="handleNavRightBack">
+            <div class="btn-span">我的</div>
+        </div>
+
         <div class="group-box">
             <div class="group__title">报修信息</div>
-            <c-select
-                title="维修分类"
-                :required="true"
-                :list="maintainTypeList"
-                pickerValueKey="name"
-                pickerValueId="id"
-                v-model="type"
-            />
-            <c-input
-                title="维修地点"
-                :required="true"
-                v-model="reason"
-             />
+            <c-select title="维修分类" :required="true" :list="maintainTypeList" pickerValueKey="name" pickerValueId="id"
+                v-model="type" />
+            <c-input title="维修地点" :required="true" v-model="reason" />
         </div>
 
-        <c-input
-            title="具体内容"
-            :required="true"
-            input-type="textarea"
-            :maxlength="800"
-            v-model="desc"
-        />
-
-        <c-files
-            ctype="images"
-            v-model="images"
-            placeholder="最多九张"
-        />
-
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-input title="具体内容" :required="true" input-type="textarea" :maxlength="800" v-model="desc" />
+
+        <c-files ctype="images" v-model="images" placeholder="最多九张" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
 
     </div>
 </template>
@@ -49,8 +29,10 @@
  */
 
 import indexMixin from '../indexMixins'
+
 import { postCreateInfo } from '@/api/approveinfo'
-import { editApprove } from '@/api/approve'
+
+import { settingNavigationRight, settingNavigationTitle } from '@/utils/dingtalk';
 
 
 export default {
@@ -58,12 +40,13 @@ export default {
     mixins: [
         indexMixin
     ],
-    data () {
+    data() {
         return {
             postApi: null,
             maintainTypeList: this.$store.state.enum.maintainTypeList,
 
             // formData start
+            way: 'create', // create/update/edit
             id: '',
             module: 8,
             reason: '', // 维修地点
@@ -76,20 +59,55 @@ export default {
         }
     },
 
-    created () {
+    created() {
+        this.navigationSetting()
         this.getCommonFlowPathData()
-        this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
+        this.postApi = postCreateInfo
     },
 
     methods: {
+        // NOTE: 设置标题等
+        navigationSetting() {
+            settingNavigationTitle({
+                title: '维修申请'
+            })
+
+            settingNavigationRight({
+                show: true,
+                control: true,
+                text: '我的出差',
+                callback: this.handleNavRightBack
+            })
+        },
+        handleNavRightBack(result) {
+            console.log('result', result);
+            this.$router.push({
+                name: 'ApplyState',
+                query: {
+                    type: this.module
+                }
+            })
+        },
+
         // 获取编辑数据
-        handleFormatEditData (data) {
-            console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
+        handleFormatEditData(data) {
+            console.log('%c edit data type8 >>>', 'background: blue; color: #fff', data);
+            const IS_EDIT = this.flag === 'approve'
+            this.way = IS_EDIT ? 'edit' : 'update'
+            this.id = IS_EDIT ? data.approve_id : data.id
+            this.reason = data.reason
+            this.desc = data.desc
+            this.type = data.type
+            if (data.module_info.images) {
+                this.images = data.module_info.images_text.map(img => ({
+                    url: img
+                }))
+            }
         },
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -97,8 +115,9 @@ export default {
             console.log('execute handleSubmitData', formData);
             this.__post__(formData)
         },
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
+                way: this.way,
                 module: this.module,
                 reason: this.reason,
                 type: this.type,
@@ -108,13 +127,14 @@ export default {
                 copy_user: this.copyPeople.map(user => (user.userid || user.emplId)).join(',')
             }
 
-            // TODO: 格式化尚未完成
-            // images
+            if (Array.isArray(this.images) && this.images.length) {
+                templateObj.images = this.images.map(item => item.url).join(',')
+            }
 
             if (this.id) templateObj.id = this.id
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'type': '维修分类',
                 'reason': '维修地点',
@@ -131,24 +151,16 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
                     this.$toast(res.msg)
-
-                    // TODO: 提交成功后跳转到我的审批
-                    /*
-                    this.$router.push({
-                        name: '',
-                        query: {
-                            formtype: this.formType
-                        }
-                    })
-                    */
-
+                    if (this.flag === 'approve') {
+                        this.$router.go(-1)
+                    } else this.__jump2apply_state__()
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },

+ 34 - 69
src/views/applyfor/components/IndexType9.vue

@@ -1,61 +1,23 @@
 <template>
     <div class="type6-container">
-        <c-select
-            title="合同类型"
-            :list="contractTypeList"
-            pickerValueKey="name"
-            pickerValueId="id"
-            v-model="type"
-        />
-
-        <c-input
-            title="合同编号"
-            :required="true"
-            v-model="reason"
-        />
-
-        <c-select
-            title="缓急程度"
-            :required="true"
-            :list="degreeList"
-            pickerValueKey="name"
-            pickerValueId="id"
-            v-model="desc"
-        />
-
-        <c-input
-            title="印制份数"
-            input-type="number"
-            v-model="number"
-        />
-
-        <c-input
-            title="发放范围"
-            placeholder="请输入发放范围,比如合同双方"
-            v-model="scope"
-        />
-
-        <c-input
-            title="法务意见"
-            placeholder="本合同已经法律顾问审核同意,详见附件《法律意见书》"
-            v-model="legal_opinion"
-        />
-
-        <c-files
-            ctype="files"
-            v-model="document"
-        />
-
-        <c-input
-            title="备注说明"
-            v-model="remark"
-        />
-
-        <c-flow-path
-            :approve="approvePeople"
-            :copy="copyPeople"
-            :isAllowCopy="isCopy"
-        />
+        <c-select title="合同类型" :list="contractTypeList" pickerValueKey="name" pickerValueId="id" v-model="type" />
+
+        <c-input title="合同编号" :required="true" v-model="reason" />
+
+        <c-select title="缓急程度" :required="true" :list="degreeList" pickerValueKey="name" pickerValueId="id"
+            v-model="desc" />
+
+        <c-input title="印制份数" input-type="number" v-model="number" />
+
+        <c-input title="发放范围" placeholder="请输入发放范围,比如合同双方" v-model="scope" />
+
+        <c-input title="法务意见" placeholder="本合同已经法律顾问审核同意,详见附件《法律意见书》" v-model="legal_opinion" />
+
+        <c-files ctype="files" v-model="document" />
+
+        <c-input title="备注说明" v-model="remark" />
+
+        <c-flow-path :approve="approvePeople" :copy="copyPeople" :isAllowCopy="isCopy" />
 
     </div>
 </template>
@@ -69,21 +31,20 @@
 
 import indexMixin from '../indexMixins'
 import { postCreateInfo } from '@/api/approveinfo'
-import { editApprove } from '@/api/approve'
-
 
 export default {
     name: 'IndexType9',
     mixins: [
         indexMixin
     ],
-    data () {
+    data() {
         return {
             postApi: null,
             contractTypeList: this.$store.state.enum.contractTypeList,
             degreeList: this.$store.state.enum.degreeList,
 
             // formData start
+            way: 'create',
             id: '',
             module: 9,
             reason: '', // 合同编号
@@ -100,20 +61,24 @@ export default {
         }
     },
 
-    created () {
+    created() {
         this.getCommonFlowPathData()
-        this.postApi = this.flag === 'approve' ? editApprove : postCreateInfo
+        this.postApi = postCreateInfo
     },
 
     methods: {
         // 获取编辑数据
-        handleFormatEditData (data) {
-            console.log('%c edit data type6 >>>', 'background: blue; color: #fff', data);
+        handleFormatEditData(data) {
+            console.log('%c edit data type9 >>>', 'background: blue; color: #fff', data);
+            const IS_EDIT = this.flag === 'approve'
+            this.way = IS_EDIT ? 'edit' : 'update'
+            this.id = IS_EDIT ? data.approve_id : data.id
+            // ...
         },
         /**
          * @description 提交数据默认函数
          */
-         handleSubmitData () {
+        handleSubmitData() {
             let formData = this.__format_data__()
             console.log('format data>>>', formData);
             let bol = this.validate(formData)
@@ -121,8 +86,9 @@ export default {
             console.log('execute handleSubmitData', formData);
             this.__post__(formData)
         },
-        __format_data__ () {
+        __format_data__() {
             let templateObj = {
+                way: this.way,
                 module: this.module,
                 reason: this.reason,
                 type: this.type,
@@ -136,13 +102,12 @@ export default {
             }
 
             // TODO: 格式化尚未完成
-            // images
             // document
 
             if (this.id) templateObj.id = this.id
             return templateObj
         },
-        validate (data) {
+        validate(data) {
             let mapTxt = {
                 'reason': '合同编号',
                 'desc': '缓急程度'
@@ -157,7 +122,7 @@ export default {
                 data
             })
         },
-        async __post__ (data) {
+        async __post__(data) {
             try {
                 const res = await this.postApi(data)
                 if (res.code === 1) {
@@ -174,7 +139,7 @@ export default {
                     */
 
                 }
-            } catch(e) {
+            } catch (e) {
                 console.log('it5, __post__', e);
             }
         },

+ 63 - 53
src/views/applyfor/components/Peers.vue

@@ -2,9 +2,7 @@
     <div class="peers-info-container">
         <div class="peers__header flex flex-row flex-row-aic">
             <span class="left-title">同行人员</span>
-            <span class="right-addd"
-                @click="handleAddPeerData"
-            >添加人员</span>
+            <span class="right-addd" @click="handleAddPeerData">添加人员</span>
         </div>
         <template v-if="!peerList.length">
             <div class="peers__emptybox">
@@ -14,24 +12,20 @@
         <template v-else>
             <!-- 同行人员渲染列表 -->
             <div class="peers__mainlist">
-                <div 
-                    class="peers__row"
-                        v-for="(item, idx) in peersListCom"
-                        :key="idx"
-                    >
-                        <div class="peers__row__header flex flex-row flex-row-aic">
-                            <div class="peers__row__header__left">
-                                <span>{{ InsideOutMap[item.xtype] }}</span>
-                                <span>({{ item.xtype === 'inside' ? (item.selectDeptName || '无部门') : item.remark }})</span>
-                            </div>
-                            <div class="operate">
-                                <span @click="handleUpdateRow(item, idx)" class="update">更新</span>
-                                <span @click="handleRemoveRow(item, idx)" class="remove">删除</span>
-                            </div>
+                <div class="peers__row" v-for="(item, idx) in peersListCom" :key="idx">
+                    <div class="peers__row__header flex flex-row flex-row-aic">
+                        <div class="peers__row__header__left">
+                            <span>{{ InsideOutMap[item.xtype] }}</span>
+                            <span>({{ item.xtype === 'inside' ? (item.selectDeptName || '无部门') : item.remark }})</span>
                         </div>
-                        <div class="peers__row__foot">
-                            <span class="name">{{ item.name }}</span>
+                        <div class="operate">
+                            <span @click="handleUpdateRow(item, idx)" class="update">更新</span>
+                            <span @click="handleRemoveRow(item, idx)" class="remove">删除</span>
                         </div>
+                    </div>
+                    <div class="peers__row__foot">
+                        <span class="name">{{ item.name }}</span>
+                    </div>
                 </div>
             </div>
             <div class="peers__more" v-if="peerList.length > 2">
@@ -41,30 +35,29 @@
             </div>
         </template>
 
-        <van-action-sheet
-            v-model="actionSheetVisibility"
-            :actions="actions"
-            @select="handleActionSheetSelected"
-            cancel-text="取消"
-            close-on-click-action
-        />
+        <van-action-sheet v-model="actionSheetVisibility" :actions="actions" @select="handleActionSheetSelected"
+            cancel-text="取消" close-on-click-action />
     </div>
 </template>
 
 <style lang="less" scoped>
 @import url('@/styles/variables.less');
+
 .peers {
+
     // &-info-container {}
     &__header {
         justify-content: space-between;
         padding: 4px 12px;
         box-sizing: border-box;
+
         .left-title {
             font-size: @font-size-third;
             font-weight: 400;
             color: #727273;
             line-height: 24px;
         }
+
         .right-addd {
             font-size: 12px;
             font-weight: 400;
@@ -72,6 +65,7 @@
             line-height: 24px;
         }
     }
+
     &__emptybox {
         padding: 15px 12px;
         background-color: #fff;
@@ -80,34 +74,42 @@
         color: #191A1E;
         line-height: 20px;
     }
+
     &__mainlist {
         padding: 8px 0;
         background-color: @white;
         border-bottom: 1px solid rgba(151, 151, 151, 0.4);
     }
+
     &__row {
         padding: 8px 12px 0;
+
         &__header {
             justify-content: space-between;
+
             &__left {
                 font-size: 14px;
                 font-weight: 400;
                 color: #191A1E;
                 line-height: 20px;
             }
+
             .operate {
                 font-size: 14px;
                 font-weight: 400;
                 color: #3290C4;
                 line-height: 20px;
+
                 .remove {
                     color: #F45642;
                     padding-left: 10px;
                 }
             }
         }
+
         &__foot {
             border-bottom: 1px solid rgba(151, 151, 151, 0.4);
+
             .name {
                 font-size: 16px;
                 font-weight: 400;
@@ -115,12 +117,14 @@
                 line-height: 30px;
             }
         }
+
         &:last-child {
             .peers__row__foot {
                 border-bottom: initial;
             }
         }
     }
+
     &__more {
         padding: 12px 0;
         text-align: center;
@@ -150,7 +154,7 @@ const InsideOutMap = {
 export default {
     name: 'Peers',
     computed: {
-        peersListCom () {
+        peersListCom() {
             if (this.isShowMore) return [...this.peerList]
             return [...this.peerList.slice(0, 2)]
         },
@@ -161,14 +165,14 @@ export default {
             require: true
         }
     },
-    created () {
+    created() {
         bus.$on('addOutPeersEvent', (data) => {
             console.log('add out peers data', data);
             // 调用外部人员[增加/修改]人员增加
             this.__handle_out_peers(data)
         })
     },
-    data () {
+    data() {
         return {
             InsideOutMap,
             isShowMore: true,
@@ -191,8 +195,22 @@ export default {
             ],
         }
     },
+    mounted() {
+        this.renderValue()
+    },
     methods: {
-        async handleActionSheetSelected (item) {
+        // 可以外部调用次方法用于更新value字段
+        renderValue() {
+            if (Array.isArray(this.value) && this.value.length) {
+                this.peerList = [...this.value].map(user => ({
+                    ...user,
+                    xtype: user.is_who ? 'out' : 'inside',
+                    remark: user.is_who ? user.desc : '',
+                    selectDeptName: user.is_who ? '' : user.desc
+                }))
+            }
+        },
+        async handleActionSheetSelected(item) {
             const { type } = item
             console.log('select', item.type, item);
             if (type === 'in') {// 内部人员
@@ -204,10 +222,10 @@ export default {
                 } catch (e) {
                     console.log('err', e);
                 }
-                
+
             } else if (type === 'out') {
                 // TODO: TEMPORARY: example
-                this.__handle_out_peers({ xtype:'out', name: `a${Date.now()}`, remark: '123333'})
+                this.__handle_out_peers({ xtype: 'out', name: `a${Date.now()}`, remark: '123333' })
 
                 // TEMPORARY: 添加外部人员
                 // this.$router.push({
@@ -217,19 +235,18 @@ export default {
                 //         remark: ''
                 //     },
                 // })
-
             }
         },
         // NOTE: 展开/收齐更多
-        handleShowMore () {
+        handleShowMore() {
             this.isShowMore = !this.isShowMore
         },
         // 更新当前人员信息
-        handleUpdateRow (row, idx) {
+        handleUpdateRow(row, idx) {
             console.log('handleUpdateRow', row, idx);
         },
         // 删除当前人员
-        handleRemoveRow (row, idx) {
+        handleRemoveRow(row, idx) {
             console.log('handleRemoveRow', row, idx);
             Dialog.confirm({
                 title: '温馨提示',
@@ -239,11 +256,11 @@ export default {
             })
         },
         // NOTE: 选择添加内部/外部人员
-        handleAddPeerData () {
+        handleAddPeerData() {
             this.actionSheetVisibility = true
         },
         // 更新外部人员
-        __handle_out_peers (data) {
+        __handle_out_peers(data) {
             if (data.isUpdate) { // Update
                 let fIdx = this.peerList.findIndex(item => item.idx === data.idx)
                 this.peerList[fIdx] = {
@@ -257,10 +274,10 @@ export default {
                     ...data
                 })
             }
-            this.$emit('input', this.peerList)
+            this.$forceUpdate()
         },
 
-        __handle_in_press__ (data) {
+        __handle_in_press__(data) {
             const { users } = data
             // console.log('handle_in_press', data);
             users.forEach(item => {
@@ -283,20 +300,13 @@ export default {
         }
     },
     watch: {
-        value: {
-            handler(arrs) {
-                if (arrs) {
-                    console.log('peers val', arrs);
-                    this.peerList = [...arrs].map(user => ({
-                        ...user,
-                        xtype: user.is_who ? 'out' : 'inside',
-                        remark: user.is_who ? user.desc : '',
-                        selectDeptName: user.is_who ? '' : user.desc
-                    }))
+        peerList: {
+            handler(vals) {
+                if (vals.length) {
+                    console.log('%c peerList >>>', 'background: blue; color: #fff', vals);
+                    this.$emit('input', vals)
                 }
-            },
-            immediate: true,
-            deep: true
+            }
         }
     }
 }

+ 46 - 35
src/views/applyfor/index.vue

@@ -1,33 +1,28 @@
 <!-- 申请主页 -->
 <template>
     <div class="apply-for-container">
-        <component
-            ref="rendeRef"
-            :flag="flag"
-            :editId="editId"
-            :edit-data="editData"
-            :is="renderComponent"
-        />
+        <component ref="rendeRef" :flag="flag" :editId="editId" :edit-data="editData" :is="renderComponent" />
 
         <!-- btnbox -->
         <div class="btnbox">
-            <div class="btn" @click="handleSubmitData">提交</div>
+            <div class="btn" @click="handleSubmitData">{{ flag === 'approve' ? '更新内容' : '提交' }}</div>
         </div>
-
-        <bizCont />
     </div>
 </template>
 
 <style lang="less">
 @import url("@/styles/variables.less");
+
 .apply-for {
     &-container {
         .layout-container {
-            margin-top: 10px!important;
+            margin-top: 10px !important;
         }
+
         .custom-files-container {
             margin-top: 10px;
         }
+
         .group-box {
             .group__title {
                 font-size: @font-size-third;
@@ -37,18 +32,22 @@
                 line-height: 28px;
                 padding: 0 12px;
             }
+
             .layout-container {
-                margin-top: 0!important;
+                margin-top: 0 !important;
             }
-            > div:not(.group__title,:last-child) {
-                border-bottom: 1px solid rgba(255, 151, 151, 0.2)!important;
+
+            >div:not(.group__title, :last-child) {
+                border-bottom: 1px solid rgba(255, 151, 151, 0.2) !important;
             }
         }
+
         .btnbox {
             margin-top: 10px;
             padding: 10px 14px 40px;
             box-sizing: border-box;
             background-color: #FFFFFF;
+
             .btn {
                 height: 41px;
                 background: #3290C4;
@@ -65,7 +64,7 @@
 
 <script>
 // components
-import bizCont from '@/components/jsapi/biz.contact.complexPicker' // useless
+// import bizCont from '@/components/jsapi/biz.contact.complexPicker' // useless
 
 // components
 import IndexType1 from './components/IndexType1.vue';
@@ -85,6 +84,25 @@ import * as approveInfoApi from '@/api/approveinfo'
 import * as approveApi from '@/api/approve'
 
 export default {
+    beforeRouteEnter(to, from, next) {
+        // if (to.name === 'Applyfor') {
+        //     if (!to.meta.keepAlive) {
+        //         to.meta.keepAlive = true
+        //     }
+        // }
+        console.log(' beforeRouteEnter >>>', to.name, to.meta, from.name);
+        next()
+    },
+    // NOTE: 只有退出applyfor/xxx页面时才清除缓存
+    beforeRouteLeave(to, from, next) {
+        if (!to.path.includes('applyfor')) {
+            from.meta.keepAlive = false
+        } else {
+            from.meta.keepAlive = true
+        }
+        console.log('%c beforeRouteLeave >>>', 'background: blue; color: #fff', to, from);
+        next()
+    },
     name: 'Applyfor',
     components: {
         IndexType1,
@@ -98,21 +116,19 @@ export default {
         IndexType9,
         IndexType10,
         IndexType11,
-        bizCont
+        // bizCont
     },
     computed: {
         // 获取需要渲染的组件
-        renderComponent () {
+        renderComponent() {
             const TYPE = this.formType
             return `IndexType${TYPE}`
         },
     },
 
-    created () {
-        console.log('%c Apply for crated >>>', 'background: blue; color: #fff', this.$route.query);
-        
+    created() {
         if (this.$route.query.type) this.formType = Number(this.$route.query.type)
-        
+
         // check is edit
         if (this.$route.query.edit == 1) {
             this.editId = Number(this.$route.query.id)
@@ -120,13 +136,12 @@ export default {
             this.flag = this.$route.query.flag
         }
 
-        this.init ()
+        this.init()
     },
 
-    data () {
+    data() {
         return {
             formType: -1, // 代表某申请类型
-
             flag: '', // [info, approve] // 页面状态 info: 申请 approve: 审核
             isEdit: false, // 是否编辑
             editId: -1, // 编辑Id
@@ -135,22 +150,18 @@ export default {
     },
 
     methods: {
-        init () {
-            // NOTE: 判断
-            if (this.isEdit) {
-                this.__detail__()
-            }
+        init() {
+            if (this.isEdit) this.__detail__()
         },
 
         // NOTE: 因为是编辑 需要判断接口
         // TODO: 缺少
-        async __detail__ () {
+        async __detail__() {
             try {
-                console.log('%c printlog >>>', 'background: blue; color: #fff', approveInfoApi, approveApi);
-                
                 const func = this.flag === 'info' ? approveInfoApi.getInfo : approveApi.getInfo
+                let paramsId = this.flag === 'info' ? 'id' : 'approve_id'
                 const params = {
-                    id: this.editId
+                    [paramsId]: this.editId
                 }
                 const result = await func(params)
                 if (result.code === 1) {
@@ -160,8 +171,8 @@ export default {
                 console.log('aplyof error >>>', error)
             }
         },
-        
-        handleSubmitData () {
+
+        handleSubmitData() {
             let callback = this.$refs.rendeRef.handleSubmitData
             callback && callback()
         }

+ 12 - 4
src/views/applyfor/indexMixins.js

@@ -4,7 +4,6 @@ import { getStringTye } from '@/utils/util'
 import indexComponentsMixins from './js/IndexComponentsMixins'
 import { getApproveFlowPath } from '@/api/approveflow'
 
-
 export default {
     mixins: [
         indexComponentsMixins
@@ -44,9 +43,6 @@ export default {
 
                 // NOTE: moduel = [5, 6]时,需要填写 `flow_item`字段。 取值 `options.flow_item`; 获取审批流程
                 if ([5, 6].includes(module) && options.flow_item) params['flow_item'] = options.flow_item
-
-                console.log('%c getCommonFlowPathData Params >>>', 'background: blue; color: #fff', params);
-                
                 const res = await getApproveFlowPath(params)
 
                 if (res.code === 1) {
@@ -122,6 +118,18 @@ export default {
                 return true
             }
         },
+
+        /**
+         * @description 跳转我的申请列表页面
+         */
+        __jump2apply_state__ () {
+            this.$router.push({
+                name: 'ApplyState',
+                query: {
+                    type: this.module
+                }
+            })
+        }
     },
     watch: {
         editData: {

+ 45 - 59
src/views/approve/components/ApproveControl.vue

@@ -2,11 +2,12 @@
     <div class="approve-control-container flex flex-row flex-row-aic">
         <!-- 
             flag = info 几种状态
-            2处理中: 催办,修改(disabled),撤销,下载文件
+            2处理中: 催办,撤销,下载文件
             3通过: 催办(disabled),修改(disabled), 撤销,下载
             4已驳回:催办(disabled),修改,撤销,下载
             5撤销:重新发起
          -->
+
         <!-- 
             flag = approve 几种状态
             [待处理,已处理,收到的]
@@ -15,46 +16,25 @@
                 通过(我的维修):上传反馈结果,下载文件
             我的收到:无任何操作权限
          -->
-        <!-- 审核通过
-            下载文件
-        -->
-
-        <!-- 领导审批
-            提醒,修改,下载文件;拒绝按钮,同意按钮
-        -->
-
-        <!-- 提交人
-        催办,修改,撤销,下载文件
-        -->
 
-        <!-- 
-            催办,修改,撤销,提醒,下载文件;拒绝按钮,同意按钮
-         -->
-
-         <!-- TODO: class 这块 还需要根据审核到某块禁用某些功能 -->
-         <div
-            :class="[
-                'item',
-                item.disable ? 'item--disable' : ''
-            ]"
-            v-for="(item, idx) in controlComputed"
-            :key="idx"
-            @click="() => (!item.disable && item.event())"
-         >
+        <div :class="[
+            'item',
+            item.disable ? 'item--disable' : ''
+        ]" v-for="(item, idx) in controlComputed" :key="idx" @click="() => (!item.disable && item.event())">
             <div class="icon">
                 <img :src="item.img" :alt="item.title">
             </div>
             <span>{{ item.title }}</span>
-         </div>
-         <!-- 审核才出现按钮 -->
-         <div class="btnd flex flex-row flex-row-aic" v-if="btnIshow">
+        </div>
+        <!-- 审核才出现按钮 -->
+        <div class="btnd flex flex-row flex-row-aic" v-if="btnIshow">
             <div class="btn" @click="handleGoExaminePage('refuse')">
                 拒绝
             </div>
-            <div class="btn btn--primary"  @click="handleGoExaminePage('pass')">
+            <div class="btn btn--primary" @click="handleGoExaminePage('pass')">
                 同意
             </div>
-         </div>
+        </div>
     </div>
 </template>
 
@@ -70,7 +50,7 @@ export default {
             require: true
         },
         module: { // NOTE: 模块
-            validator: num => ([1,2,3,4,5,6,7,8,9,10,11].includes(num))
+            validator: num => ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].includes(num))
         },
         flag: {
             validator: flag => (['info', 'approve'].includes(flag))
@@ -80,9 +60,9 @@ export default {
         },
     },
     computed: {
-        controlComputed () {
+        controlComputed() {
             let flag = this.flag
-            let state = this.flagState
+            let state = Number(this.flagState)
             let module = this.module
             console.log(flag, state, module);
             const [urging, edit, revoke, ding, print, REISSUE, pushResult] = this.control
@@ -90,23 +70,21 @@ export default {
 
             if (flag === 'info') {
                 // 审批状态:2=审批中,3=审批通过,4=审批驳回,5=审批撤销  
-                // state = 2,3,4,5
                 switch (state) {
                     case 2:
                         temparr = [
                             urging,
-                            {
-                                // TEMPORARY: 临时改动禁用为false
-                                ...edit,
-                                disable: false
-                            },
+                            // {
+                            //     ...edit,
+                            //     disable: true
+                            // },
                             revoke,
                             print
                         ]
                         break;
                     case 3:
                         temparr = [
-                            { ...urging, disable: true},
+                            { ...urging, disable: true },
                             { ...edit, disable: true },
                             revoke,
                             print
@@ -114,7 +92,7 @@ export default {
                         break;
                     case 4:
                         temparr = [
-                            {...urging, disable: true},
+                            { ...urging, disable: true },
                             edit,
                             revoke,
                             print
@@ -127,8 +105,8 @@ export default {
                         break;
                 }
             } else if (flag === 'approve') {
-                switch(state) {
-                    // 待审核,已审核,收到的;三种状态
+                switch (state) {
+                    // 2待审核,3已审核,4收到的;三种状态
                     case 2:
                         temparr = [
                             ding,
@@ -140,16 +118,16 @@ export default {
                         if (module === 8) temparr.push(pushResult)
                         temparr.push(print)
                         break;
-                    // case 4:
+                    // case 4: // 收到的没有状态
                 }
             }
             return temparr
         },
-        btnIshow () {
-            return this.flag === 'approve'
+        btnIshow() {
+            return this.flag === 'approve' && Number(this.flagState) === 2
         },
     },
-    data () {
+    data() {
         return {
             type: 3,
             control: [ // NOTE: [WARNING] 顺序不可更改。
@@ -200,14 +178,14 @@ export default {
         }
     },
     methods: {
-        handleEvent () {
+        handleEvent() {
             this.$toast('等待功能实现中')
         },
         // NOTE: 提醒
         // TODO: 申请提醒/审批提醒
-        async handleDingEvent () {
+        async handleDingEvent() {
             try {
-                const func = this.flag === 'info' ? putUrging : () => {}
+                const func = this.flag === 'info' ? putUrging : () => { }
                 const params = {
                     id: this.id
                 }
@@ -220,9 +198,9 @@ export default {
             }
         },
         // NOTE: 驳回
-        async handleRevokeEvent () {
+        async handleRevokeEvent() {
             try {
-                const func = this.flag === 'info' ? putCancel : () => {}
+                const func = this.flag === 'info' ? putCancel : () => { }
                 const params = {
                     id: this.id
                 }
@@ -237,16 +215,17 @@ export default {
         },
         // NOTE: 下载文件
         // TODO: 下载文件尚未拥有
-        handleDownloadFileEvent () {
+        handleDownloadFileEvent() {
             try {
                 this.$toast('功能迭代中...')
             } catch (error) {
                 console.log('download file err>>', error);
             }
         },
-        handleEditEvent () {
-            // TODO: 修改跳转填写页面
-            this.$router.replace({
+
+        // NOTE: 修改跳转填写页面
+        handleEditEvent() {
+            this.$router.push({
                 name: 'Applyfor',
                 query: {
                     type: this.module,
@@ -256,7 +235,8 @@ export default {
                 }
             })
         },
-        handleGoExaminePage (type) {
+
+        handleGoExaminePage(type) {
             console.log('type', type);
             this.$router.push({
                 name: 'Examine',
@@ -272,11 +252,13 @@ export default {
 
 <style lang="less" scoped>
 @import url("@/styles/variables.less");
+
 .approve-control {
     &-container {
         padding: 11px 24px 30px;
         background-color: #f2f1f6;
         justify-content: space-between;
+
         .item {
             display: flex;
             flex-direction: column;
@@ -288,9 +270,11 @@ export default {
             font-weight: 400;
             color: #151419;
             line-height: 18px;
+
             &--disable {
                 opacity: 0.5;
             }
+
             .icon {
                 img {
                     width: 24px;
@@ -298,6 +282,7 @@ export default {
                 }
             }
         }
+
         .btnd {
             .btn {
                 width: 56px;
@@ -312,11 +297,12 @@ export default {
                 font-size: @font-size-common;
                 font-weight: 400;
                 color: #191A1E;
-                
+
                 &--primary {
                     background: #3290C4;
                     color: @white;
                 }
+
                 &:last-child {
                     margin-right: initial;
                 }

+ 58 - 31
src/views/approve/components/ApproveFlowPath.vue

@@ -5,39 +5,35 @@
         </div>
         <div class="flow-path-main">
             <!-- 发起人 -->
-            <!-- TODO: 发起人需要后端数据携带才行 -->
-            <div class="row flex flex-row">
+            <div class="row flex flex-row" v-if="create">
                 <div class="row__line"></div>
                 <div class="avatar avatar--name">
-                    <span class="avatar__name">刘辉</span>
-                    <div class="status-bar">
-                        <van-icon color="#15BC83" :size="16" name="checked" />
-                    </div>
+                    <template v-if="create.avatar">
+                        <img class="avatar-heade" :src="create.avatar" />
+                    </template>
+                    <template v-else>
+                        <span class="avatar__name">{{ create.name | changeName }}</span>
+                    </template>
+                    <!-- TODO: 状态是否需要 -->
+                    <!-- <div class="status-bar">
+                        <van-icon color="rgba(254, 148, 62, 1)" :size="16" name="more" />
+                    </div> -->
                 </div>
                 <div class="row-main">
                     <div class="header flex flex-row flex-row-aic">
                         <span class="header__title">发起申请</span>
-                        <span class="header__time">11-07 19:12</span>
+                        <span class="header__time">{{ create.create_at }}</span>
                     </div>
                     <div class="mainbox flex flex-row flex-row-aic">
                         <div class="mainbox__cur-name">
-                            刘辉(发起人)
-                        </div>
-                        <div class="mainbox__cur-use-time">
-                            <!-- 平均审批时长:0天0时23分 -->
+                            {{ create.name }}(发起人)
                         </div>
                     </div>
-                    <div class="footerinfo">
-                        <!-- <div class="messagebox"></div> -->
-                    </div>
                 </div>
             </div>
 
             <!-- 审批人 -->
-            <div class="row flex flex-row"
-                v-for="(person, idx) in approveList"
-                :key="idx"
-            >
+            <div class="row flex flex-row" v-for="(person, idx) in approveList" :key="idx">
                 <div class="row__line"></div>
                 <div class="avatar avatar--name">
                     <template v-if="person.user.avatar">
@@ -57,7 +53,8 @@
                     </div>
                     <div class="mainbox flex flex-row flex-row-aic">
                         <div class="mainbox__cur-name">
-                            {{ person.user.name }}(<span :class="handleMapClass(person.status)">{{ person.status | filterFlowPathStatusTxt }}</span>)
+                            {{ person.user.name }}(<span :class="handleMapClass(person.status)">{{ person.status |
+                                filterFlowPathStatusTxt }}</span>)
                         </div>
                         <div class="mainbox__cur-use-time" v-if="person.time_text">
                             平均审批时长:{{ person.time_text }}
@@ -96,15 +93,13 @@
                     </div>
                     <div class="footerinfo footerinfo--ptop10">
                         <div v-show="seeMoreCopy" class="recive-of flex flex-row flex-row-aic">
-                            <div class="personal flex flex-col flex-col-aic"
-                                v-for="(personal, idx) in copys"
-                                :key="idx"
-                            >
+                            <div class="personal flex flex-col flex-col-aic" v-for="(personal, idx) in copys" :key="idx">
                                 <div class="avatar avatar--name">
                                     <span class="avatar__name">{{ personal.user.name | changeName }}</span>
                                     <div class="status-bar" v-if="false">
                                         <!-- NOTE: (后台与产品咨询。并无抄送人状态) 查看Status暂时无数据 -->
-                                        <van-icon v-if="personal.approve_flow === 1" color="#15BC83" :size="12" name="checked" />
+                                        <van-icon v-if="personal.approve_flow === 1" color="#15BC83" :size="12"
+                                            name="checked" />
                                         <van-icon v-else color="rgba(254, 148, 62, 1)" :size="12" name="more" />
                                     </div>
                                 </div>
@@ -125,6 +120,10 @@ import store from '@/store';
 
 export default {
     props: {
+        create: {
+            type: Object,
+            default: () => null
+        },
         approveList: {
             type: Array,
             default: () => ([])
@@ -152,23 +151,23 @@ export default {
         handleSwitchreciveMore() {
 
         },
-        handleMapClass (status) {
+        handleMapClass(status) {
             let className = 'approve--'
-            switch(status) {
+            switch (status) {
                 case 1:
                 case 2:
                 case 3:
                     className += 'common'
-                break;
+                    break;
                 case 4:
                     className += 'refuse'
-                break;
+                    break;
             }
             return className
         }
     },
     filters: {
-        filterFlowPathStatusTxt (status) {
+        filterFlowPathStatusTxt(status) {
             return store.getters['enum/getApproveFlowPathEnum'](status)
         }
     },
@@ -184,6 +183,7 @@ export default {
         background-color: @white;
         margin-top: 10px;
     }
+
     &__title {
         font-size: @font-size-secondery;
         font-weight: 600;
@@ -196,6 +196,7 @@ export default {
 .row {
     position: relative;
     margin-bottom: 43px;
+
     .avatar {
         position: relative;
         width: 36px;
@@ -203,6 +204,7 @@ export default {
         background: #3290C4;
         border-radius: 4px;
         margin-right: 18px;
+
         // margin-bottom: 4px;
         &--name {
             display: flex;
@@ -210,9 +212,11 @@ export default {
             align-items: center;
             justify-content: center;
         }
+
         &--volume {
             background-color: rgba(79, 148, 236, 1);
         }
+
         &__name {
             font-size: @font-size-third;
             font-family: PingFangSC-Regular, PingFang SC;
@@ -220,12 +224,14 @@ export default {
             color: #FFFFFF;
             line-height: 9px;
         }
+
         &-heade {
             width: 100%;
             height: 100%;
             vertical-align: middle;
             border-radius: 4px;
         }
+
         .status-bar {
             position: absolute;
             right: 0;
@@ -239,6 +245,7 @@ export default {
             border-radius: 14px;
             transform: translate(30%, 30%);
         }
+
         // &::after {
         //     position: absolute;
         //     content: "";
@@ -248,8 +255,9 @@ export default {
         //     height: 100%;
         //     background-color: #E3E3E4;
         // }
-        
+
     }
+
     // &:last-child {
     //     .avatar::after {
     //         width: 0;
@@ -264,10 +272,13 @@ export default {
         height: 100%;
         background-color: #E3E3E4;
     }
+
     &-main {
         flex: 1;
+
         .header {
             justify-content: space-between;
+
             &__title {
                 font-size: @font-size-third;
                 font-family: PingFangSC-Regular, PingFang SC;
@@ -275,6 +286,7 @@ export default {
                 color: #9A9A9A;
                 line-height: 18px;
             }
+
             &__time {
                 font-size: @font-size-third;
                 font-family: PingFangSC-Regular, PingFang SC;
@@ -283,14 +295,17 @@ export default {
                 line-height: 16px;
             }
         }
+
         .mainbox {
             justify-content: space-between;
+
             &__cur-name {
                 font-size: @font-size-common;
                 font-weight: 400;
                 color: #191A1E;
                 line-height: 18px;
             }
+
             &__cur-use-time {
                 font-size: @font-size-third;
                 font-family: PingFangSC-Regular, PingFang SC;
@@ -299,11 +314,13 @@ export default {
                 line-height: 16px;
             }
         }
+
         .footerinfo {
             &--ptop10 {
                 padding-top: 6px;
-                
+
             }
+
             .messagebox {
                 width: 100%;
                 background: #F2F1F6;
@@ -316,16 +333,20 @@ export default {
                 padding: 9px 8px;
                 box-sizing: border-box;
             }
+
             .recive-of {
                 flex-wrap: wrap;
+
                 .avatar {
                     width: 21px;
                     height: 21px;
                     font-size: @font-size-third;
+
                     &__name {
                         transform: scale(0.6);
                         white-space: nowrap;
                     }
+
                     .status-bar {
                         width: 12px;
                         height: 12px;
@@ -335,8 +356,10 @@ export default {
                         transform: translate(38%, 48%);
                     }
                 }
+
                 .personal {
                     margin-bottom: 10px;
+
                     &__name {
                         font-size: @font-size-third;
                         font-family: PingFangSC-Regular, PingFang SC;
@@ -352,12 +375,15 @@ export default {
     &:last-child {
         margin-bottom: 20px;
     }
+
     &-copy {
         .footerinfo .avatar {
             margin-right: initial;
         }
+
         .personal {
             margin-right: 10px;
+
             &:last-child {
                 margin-right: initial;
             }
@@ -369,6 +395,7 @@ export default {
     &--common {
         color: #191A1E;
     }
+
     &--refuse {
         color: #F45642;
     }

+ 39 - 26
src/views/approve/components/DetailRows.vue

@@ -13,6 +13,7 @@
                 <van-icon v-else name="arrow-down" />
             </div>
         </div>
+
         <div v-if="[undefined, ''].includes(type)" class="value value--common">{{ value }}</div>
         <div class="value value--link" v-else-if="type === 'link'">{{ value }}</div>
 
@@ -25,22 +26,15 @@
         <!-- TODO: 明细 后期会有更加细致的划分。 因为有11种模块 -->
         <template v-else-if="type === 'projects'">
             <!-- 采购商品明细 -->
-
             <div class="projects-box-wrapper">
-                <div class="projects-box"
-                    v-for="(item, idx) in value"
-                    :key="idx"
-                >
+                <div class="projects-box" v-for="(item, idx) in value" :key="idx">
                     <div class="projects__header flex flex-row flex-row--aic">
                         <div class="title">{{ item.projectName }}</div>
                         <div class="count">x{{ item.count }}</div>
                     </div>
                     <div class="projects__footer flex flex-row flex-row-aic">
                         <div class="tags">
-                            <span
-                                v-for="(tag, tagidx) in item.tags"
-                                :key="tagidx"
-                            >
+                            <span v-for="(tag, tagidx) in item.tags" :key="tagidx">
                                 {{ tag }} {{ item.tags.length - 1 !== tagidx ? ';' : '' }}
                             </span>
                         </div>
@@ -50,17 +44,14 @@
                     </div>
                 </div>
             </div>
-        
+
         </template>
 
 
         <!-- NOTE: 附件材料 -->
         <template v-else-if="type === 'files'">
             <div class="files-container">
-                <div class="files-row flex flex-row flex-row-aic"
-                    v-for="(file, idx) in value"
-                    :key="idx"
-                >
+                <div class="files-row flex flex-row flex-row-aic" v-for="(file, idx) in value" :key="idx">
                     <div class="icon">
                         <!-- NOTE: 根据文件类型放置Icon -->
                     </div>
@@ -79,10 +70,7 @@
         <!-- NOTE:图片 -->
         <template v-else-if="type === 'images'">
             <div class="images-container flex flex-row">
-                <div class="images-row"
-                    v-for="(image, idx) in value"
-                    :key="idx"
-                >
+                <div class="images-row" v-for="(image, idx) in value" :key="idx" @click="handleReviewImages(value, idx)">
                     <img :src="image.url" :alt="image.name" />
                 </div>
             </div>
@@ -92,6 +80,7 @@
 </template>
 
 <script>
+import { ImagePreview } from 'vant'
 
 export default {
     props: {
@@ -117,18 +106,27 @@ export default {
         }
     },
     computed: {
-        moreText () {
+        moreText() {
             return this.more ? '收起' : '展开'
         },
     },
-    data () {
+    data() {
         return {
             more: true, // 展开与收起的`more`key
         }
     },
     methods: {
+        // TODO: Review files
         handleReviewFiles(file, index) {
             console.log('handleReviewFile', file, index);
+        },
+
+        // NOTE: Review images
+        handleReviewImages(files, idx) {
+            ImagePreview({
+                images: files.map(file => file.url),
+                startPosition: idx
+            })
         }
     }
 
@@ -137,6 +135,7 @@ export default {
 
 <style lang="less">
 @import url("@/styles/variables.less");
+
 .detail-rows {
     &-container {
         &__title {
@@ -145,11 +144,13 @@ export default {
             font-weight: 400;
             color: #727273;
             line-height: 20px;
+
             .more-box {
                 font-size: @font-size-third;
                 font-weight: 400;
                 color: #3290C4;
                 line-height: 12px;
+
                 .van-icon {
                     margin-left: 2px;
                 }
@@ -161,9 +162,11 @@ export default {
             font-weight: 600;
             font-weight: 400;
             line-height: 24px;
+
             &--common {
                 color: #191A1E;
             }
+
             &--link {
                 color: @link-color;
             }
@@ -176,7 +179,9 @@ export default {
                 background-color: rgba(248, 248, 248, 1);
                 border-radius: 7px;
             }
+
             &-box {
+
                 .title,
                 .tags {
                     font-size: @font-size-common;
@@ -191,6 +196,7 @@ export default {
                     color: #727273;
                     line-height: 18px;
                 }
+
                 &:last-child {
                     .projects__footer {
                         border-bottom: initial;
@@ -199,17 +205,20 @@ export default {
                     }
                 }
             }
+
             &__header {
                 justify-content: space-between;
                 padding-bottom: 10px;
                 overflow: hidden;
             }
+
             &__footer {
                 justify-content: space-between;
                 padding-bottom: 10px;
                 border-bottom: 1px solid #D8D8D8;
                 margin-bottom: 10px;
                 overflow: hidden;
+
                 .money {
                     font-size: @font-size-common;
                     font-weight: 500;
@@ -221,9 +230,8 @@ export default {
 
         // 附件样式
         .files {
-            &-comtainer {
+            &-comtainer {}
 
-            }
             &-row {
                 .icon {
                     width: 35px;
@@ -231,18 +239,20 @@ export default {
                     background: #FFCF95;
                     margin-right: 12px;
                 }
-                &__info {
 
-                }
+                &__info {}
             }
+
             &-name {
                 font-size: @font-size-common;
                 font-weight: 400;
                 color: #191A1E;
                 line-height: 18px;
             }
+
             &-other-info {
                 margin-top: 4px;
+
                 .size {
                     font-size: @font-size-third;
                     font-weight: 400;
@@ -250,6 +260,7 @@ export default {
                     line-height: 18px;
                     margin-right: 6px;
                 }
+
                 .review {
                     font-size: @font-size-third;
                     font-weight: 400;
@@ -262,17 +273,20 @@ export default {
         // 图片Style
         .images {
             &-container {
-                flex-wrap: nowrap;
+                flex-wrap: wrap;
             }
+
             &-row {
                 width: 48px;
                 height: 48px;
                 margin-right: 10px;
                 margin-bottom: 10px;
+
                 &:last-child {
                     margin-right: initial;
                     // margin-bottom: initial;
                 }
+
                 img {
                     width: 48px;
                     height: 48px;
@@ -285,5 +299,4 @@ export default {
         }
     }
 }
-
 </style>

+ 177 - 135
src/views/approve/detail.vue

@@ -8,7 +8,12 @@
                 <van-icon name="chat-o" />
                 <span>{{ schoolName }}</span>
             </div>
-            <div class="status-bar status-bar--warning">
+
+            <!-- TODO: 审核样式 -->
+            <div :class="[
+                'status-bar',
+                renderStatusBarClass
+            ]">
                 <span>{{ approveStatusMap }}</span>
             </div>
 
@@ -18,38 +23,23 @@
             </div>
         </div>
 
-
         <!-- 各种审批内容组件 -->
         <div class="examine-detail__main">
-            <detail-rows
-                class="detail-row"
-                v-for="(row, idx) in datalist"
-                :key="idx"
-                v-bind="row"
-            />
-
+            <detail-rows class="detail-row" v-for="(row, idx) in datalist" :key="idx" v-bind="row" />
         </div>
 
         <!-- 流程组件 -->
         <!-- @Description 流程化 用到的地方很多 -->
         <!-- ApproveFlowPath -->
         <div class="approve-flow-path-box">
-            <approve-flow-path
-                :approve-list="approveList"
-                :copys="approveCopyList"
-            />
+            <approve-flow-path :create="createUser" :approve-list="approveList" :copys="approveCopyList" />
         </div>
 
 
         <!-- operate. 操作台 -->
         <!-- 集成 提醒, 修改, 下载, 拒绝,同意  5种 -->
         <div class="approve-control">
-            <approve-control
-                :id="id"
-                :module="module"
-                :flag="pageType"
-                :flag-state="dataDetailStatus"
-            />
+            <approve-control :id="id" :module="module" :flag="pageType" :flag-state="dataDetailStatusComputed" />
         </div>
     </div>
 </template>
@@ -66,10 +56,14 @@ import DetailRows from './components/DetailRows.vue'
 import ApproveFlowPath from './components/ApproveFlowPath.vue'
 import ApproveControl from './components/ApproveControl.vue'
 
-import * as ApproveInfoApi from '@/api/approveinfo'
+import * as approveInfoApi from '@/api/approveinfo'
+import * as approveApi from '@/api/approve'
 
 import { mapState } from 'vuex'
 
+
+import { formatApplyforRows } from '@/utils/applyfor-item'
+
 export default {
     name: 'ExamineDetail',
     components: {
@@ -78,129 +72,164 @@ export default {
         ApproveControl
     },
     computed: {
+        dataDetailStatusComputed() {
+            let status = this.dataDetailStatus
+            let from = this.pageFrom
+            switch (from) {
+                case 'approve_3':
+                    return 4 // 审批详情。 我收到的 没有任何操作权限
+                default:
+                    return status
+            }
+        },
+
+        // 渲染审核状态样式
+        renderStatusBarClass() {
+            if (!this.dataDetail) return 'status-bar--warning'
+            const { status } = this.dataDetail
+            let className = ''
+            switch (status) {
+                case 3:
+                    className = 'status-bar--success'
+                    break
+                case 4:
+                    className = 'status-bar--danger'
+                    break
+                default:
+                    className = 'status-bar--warning'
+            }
+            return className
+        },
+
+        title() {
+            if (!this.dataDetail) return ''
+            const { create_user } = this.dataDetail
+            return `${create_user.name}提交的申请单`
+        },
         ...mapState('enum', [
             'evectionTypeList',
         ]),
-        approveStatusMap () {
+        ...mapState('user', [
+            'schoolName'
+        ]),
+        approveStatusMap() {
             if (!this.dataDetail) return ''
             let status = this.dataDetail.status
             return this.$store.getters['enum/getApproveFlowPathEnum'](status)
         }
     },
-    data () {
+    data() {
         return {
             dataDetail: null,
             isAndroid: checkPlatform() === 'android',
             isiOS: checkPlatform() === 'iOS',
 
-            // TODO: 标识标题、学校名称如何获取
-            title: '刘辉提交的申请单',
-            schoolName: '深圳市第二特殊教育学校',
-
-            datalist: [
-                {
-                    title: '审批编号',
-                    value: '20222110741458005442684',
-                },
-                {
-                    title: '合同编号',
-                    value: '20222110741458005442684',
-                    type: 'link' // 代表它是一个链接
-                },
-                {
-                    title: '所在部门',
-                    value: '深圳市第二特殊教育学校-教师部'
-                },
-                {
-                    title: '申请日期',
-                    value: '2022-11-07',
-                    type: 'date' // 代表返回的是unixtime 时间戳需要自己转义`dayjs`
-                },
-                {
-                    title: '申请人',
-                    value: '刘辉'
-                },
-                {
-                    title: '申请事由',
-                    value: '学生生活用品购买'
-                },
-                {
-                    title: '申购类型',
-                    value: '货物申购',
-                    type: 'type' // 类型字段意味着这是枚举需要自己配置 
-                },
-                {
-                    type: 'projects',
-                    title: '申购明细',
-                    value: [
-                        {
-                            projectName: '学生冬季校服',
-                            count: 20,
-                            tags: ['蓝色', '165cm'],
-                            money: 56025
-                        },
-                        {
-                            projectName: '学生冬季校服',
-                            count: 30,
-                            tags: ['蓝色', '175cm'],
-                            money: 65025
-                        }
-                    ]
-                },
-                {
-                    title: '总金额',
-                    value: '100000'
-                },
-                {
-                    title: '预计申购完成日期',
-                    value: '2022-11-08'
-                },
-                {
-                    type: 'files', // 代表当前是 上传的文件
-                    title: '附件材料',
-                    value: [
-                        {
-                            type: 'pdf',
-                            name: '采购说明.pdf',
-                            size: '264.45KB'
-                        }
-                    ]
-                },
-                {
-                    type: 'images', // 代表当前是图片组
-                    title: '图片',
-                    value: [
-                        {
-                            url: 'http://xxxxx'
-                        },
-                        {
-                            url: 'http://xxxxx'
-                        },
-                        {
-                            url: 'http://xxxxx'
-                        }
-                    ]
-                },
-                {
-                    title: '支付方式',
-                    value: '银行转账' // NOTE: 转账方式理论上来讲也是一套枚举
-                }
-            ],
+            datalist: [],
+            // datalist: [
+            //     {
+            //         title: '审批编号',
+            //         value: '20222110741458005442684',
+            //     },
+            //     {
+            //         title: '合同编号',
+            //         value: '20222110741458005442684',
+            //         type: 'link' // 代表它是一个链接
+            //     },
+            //     {
+            //         title: '所在部门',
+            //         value: '深圳市第二特殊教育学校-教师部'
+            //     },
+            //     {
+            //         title: '申请日期',
+            //         value: '2022-11-07',
+            //         type: 'date' // 代表返回的是unixtime 时间戳需要自己转义`dayjs`
+            //     },
+            //     {
+            //         title: '申请人',
+            //         value: '刘辉'
+            //     },
+            //     {
+            //         title: '申请事由',
+            //         value: '学生生活用品购买'
+            //     },
+            //     {
+            //         title: '申购类型',
+            //         value: '货物申购',
+            //         type: 'type' // 类型字段意味着这是枚举需要自己配置 
+            //     },
+            //     {
+            //         type: 'projects',
+            //         title: '申购明细',
+            //         value: [
+            //             {
+            //                 projectName: '学生冬季校服',
+            //                 count: 20,
+            //                 tags: ['蓝色', '165cm'],
+            //                 money: 56025
+            //             },
+            //             {
+            //                 projectName: '学生冬季校服',
+            //                 count: 30,
+            //                 tags: ['蓝色', '175cm'],
+            //                 money: 65025
+            //             }
+            //         ]
+            //     },
+            //     {
+            //         title: '总金额',
+            //         value: '100000'
+            //     },
+            //     {
+            //         title: '预计申购完成日期',
+            //         value: '2022-11-08'
+            //     },
+            //     {
+            //         type: 'files', // 代表当前是 上传的文件
+            //         title: '附件材料',
+            //         value: [
+            //             {
+            //                 type: 'pdf',
+            //                 name: '采购说明.pdf',
+            //                 size: '264.45KB'
+            //             }
+            //         ]
+            //     },
+            //     {
+            //         type: 'images', // 代表当前是图片组
+            //         title: '图片',
+            //         value: [
+            //             {
+            //                 url: 'http://xxxxx'
+            //             },
+            //             {
+            //                 url: 'http://xxxxx'
+            //             },
+            //             {
+            //                 url: 'http://xxxxx'
+            //             }
+            //         ]
+            //     },
+            //     {
+            //         title: '支付方式',
+            //         value: '银行转账' // NOTE: 转账方式理论上来讲也是一套枚举
+            //     }
+            // ],
 
             pageType: '', // 页面类型 info and approve
+            pageFrom: '',
             apiFunc: null, // 接口函数 
             id: '', // NOTE: 当前页面的(申请/审核)id
 
-
+            createUser: null,
             approveList: [],
             approveCopyList: [],
             dataDetailStatus: -1,
             module: undefined,
         }
     },
-    created () {
+    created() {
         const that = this
-        
+
         setTitle({
             title: '详情'
         })
@@ -222,35 +251,39 @@ export default {
     },
     methods: {
         // NOTE: 页面初始化的模块
-        __init__ () {
-            let { id, type } = this.$route.query
-            this.id = id
+        __init__() {
+            let { id, type, from } = this.$route.query
+            this.id = Number(id)
             this.pageType = type
+            this.pageFrom = from
 
+            // let paramsId = this.flag === 'info' ? 'id' : 'approve_id'
             // TODO: 请求接口&整合数据给予`datalist`字段
-            this.apiFunc = type === 'info' ? ApproveInfoApi.getDetail : () => {}
+            this.apiFunc = type === 'info' ? approveInfoApi.getDetail : approveApi.getDetail
 
             this.$nextTick(() => {
                 this.__detail__()
             })
         },
 
-
-        async __detail__ () {
+        async __detail__() {
             try {
+                let paramsId = this.pageType === 'info' ? 'id' : 'approve_id'
+
                 const params = {
-                    id: this.id
+                    [paramsId]: this.id
                 }
                 const res = await this.apiFunc(params)
                 if (res.code === 1) {
                     this.dataDetail = res.data
                     console.log(res.data);
-                    const { status, module, approve, approve_copy } = res.data
+                    const { status, module, create_user, approve, approve_copy } = res.data
                     this.module = module
                     this.dataDetailStatus = status
+                    this.createUser = create_user
                     this.approveList = approve
                     this.approveCopyList = approve_copy
-                    this.datalist = await this.formatModuleInfoData(res.data)
+                    this.datalist = formatApplyforRows(res.data)
 
                 }
             } catch (e) {
@@ -265,21 +298,20 @@ export default {
         },
 
         // NOTE: 渲染`module_info`字段函数; 让其更好的渲染
-        async formatModuleInfoData (data) {
+        async formatModuleInfoData(data) {
             const { module, order_no, module_info, department_data } = data
             let evectionTypeMap = this.evectionTypeList
             if (module === 5 && evectionTypeMap) {
                 let vops = evectionTypeMap.filter(option => (option.id === module_info.type))[0]
                 module_info.type_text = vops.name
             }
-            
             let temporaryList = [
                 {
                     title: '审批编号',
                     value: order_no
                 }
             ]
-            switch(module) {
+            switch (module) {
                 case 5:
                     temporaryList.push(...[
                         {
@@ -300,11 +332,12 @@ export default {
                         { title: '出差开始时间', value: module_info.start_time },
                         { title: '出差结束时间', value: module_info.end_time },
 
-                        module_info.document_text.length ? { title: '附件材料',
+                        module_info.document_text.length ? {
+                            title: '附件材料',
                             type: 'files',
                             value: module_info.document_text
                         } : undefined,
-                        
+
                         module_info.images_text.length ? {
                             type: 'images',
                             title: '图片',
@@ -324,7 +357,7 @@ export default {
                             value: module_info.remark
                         }
                     ])
-                break
+                    break
             }
             // NOTE: 过滤undefined的数组值
             temporaryList = temporaryList.filter(row => row)
@@ -332,13 +365,13 @@ export default {
             return Promise.resolve(temporaryList)
         }
     },
-    beforeDestroy () {
+    beforeDestroy() {
         if (this.isAndroid) {
             // 安卓移除回调
             dd.off('leftBtnClick', this.handleBackEvent)
         }
     },
-    
+
 }
 </script>
 
@@ -351,11 +384,13 @@ export default {
             margin-bottom: 10px;
         }
     }
+
     &__header {
         position: relative;
         padding: 10px 12px;
         background-color: @white;
         margin-bottom: 6px;
+
         .float-status {
             position: absolute;
             right: 12px;
@@ -366,6 +401,7 @@ export default {
             border-radius: 80px;
             overflow: hidden;
         }
+
         .title {
             font-size: 16px;
             font-family: PingFangSC-Medium, PingFang SC;
@@ -373,6 +409,7 @@ export default {
             color: #191A1E;
             line-height: 24px;
         }
+
         .location {
             span {
                 width: 137px;
@@ -385,24 +422,29 @@ export default {
                 margin-left: 6px;
             }
         }
+
         .status-bar {
             span {
                 font-size: @font-size-third;
                 font-weight: 500;
                 line-height: 18px;
             }
+
             &--success {
                 color: @status-success-color;
             }
+
             &--warning {
                 color: @status-warning-color;
             }
+
             &--danger {
                 color: @status-danger-color;
             }
 
         }
     }
+
     &__main {
         padding: 14px 12px;
         background-color: @white;

+ 5 - 11
src/views/personal/nickname.vue

@@ -1,12 +1,6 @@
 <template>
     <div class="username-container p-h-12">
-        <van-field
-            v-model="nickname"
-            clearable
-            label="昵称"
-            placeholder="请输入"
-            input-align="right"
-        />
+        <van-field v-model="nickname" clearable label="昵称" placeholder="请输入" input-align="right" />
 
         <div class="btn" @click="handleSaveOperate">submit</div>
     </div>
@@ -22,11 +16,11 @@ export default {
         updateUserInfoMixin
     ],
 
-    created () {
+    created() {
         this.nickname = this.$store.state.user.nickname
     },
 
-    data () {
+    data() {
         return {
             nickname: ''
         }
@@ -34,12 +28,12 @@ export default {
 
 
     methods: {
-        handleSaveOperate () {
+        handleSaveOperate() {
             const nickname = this.nickname
             if (!nickname) return this.$toast.fail('昵称尚未填写')
 
             const params = {
-                type: 1,
+                type: 2,
                 nickname: this.nickname
             }
             this.put_userinfo(params, true)

+ 21 - 24
src/views/personal/single-info.vue

@@ -2,11 +2,7 @@
     <!-- 个人信息页面 -->
     <div class="single-info">
         <div class="infolist">
-            <div class="row"
-                v-for="(row, idx) in infoList"
-                :key="idx"
-                @click="handleClickRow(row, idx)"
-            >
+            <div class="row" v-for="(row, idx) in infoList" :key="idx" @click="handleClickRow(row, idx)">
                 <div class="lab">{{ row.label }}</div>
                 <div class="val">
                     <template v-if="row.jumpto === 'avatar'">
@@ -23,9 +19,7 @@
         </div>
 
         <!-- 单独签名 -->
-        <div class="row single-row singlerrr"
-            @click="handleGoChange('signature')"
-        >
+        <div class="row single-row singlerrr" @click="handleGoChange('signature')">
             <div class="lab">{{ signature.label }}</div>
             <div class="val">
                 <template>
@@ -39,10 +33,7 @@
         </div>
 
         <!-- 弹窗 更新头像 -->
-        <van-popup
-            v-model="show"
-            position="bottom"
-            >
+        <van-popup v-model="show" position="bottom">
             <!-- :style="{ height: '30%' }" -->
             <div class="popup-main">
                 <div class="row-item" @click="handleOpenCamera">拍照/上传头像</div>
@@ -80,7 +71,7 @@ export default {
             department: 'getDepartments'
         })
     },
-    data () {
+    data() {
         return {
             infoList: [],
             signature: {
@@ -91,11 +82,11 @@ export default {
         }
     },
 
-    created () {
+    created() {
         this.__init__()
     },
 
-    mounted () {
+    mounted() {
         const that = this
         waitAuthentication({
             jsApiList: [],
@@ -105,10 +96,10 @@ export default {
     },
 
     methods: {
-        handleAError (error) {
+        handleAError(error) {
             console.log('error', error);
         },
-        handleAReady (){
+        handleAReady() {
             console.log('%c 添加中转Key 告知用户是否可以进行上传头像 >>>', 'background: blue; color: #fff');
         },
         __init__() {
@@ -116,12 +107,12 @@ export default {
             that.infoList = [
                 {
                     label: '头像',
-                    pic: that.avatar, 
+                    pic: that.avatar,
                     jumpto: 'avatar'
                 },
                 {
                     label: '昵称',
-                    val: that.username,
+                    val: that.nickname,
                     jumpto: 'nickname'
                 },
                 {
@@ -143,7 +134,7 @@ export default {
             that.signature.state = that.signatureStateText
         },
 
-        handleGoChange (state) {
+        handleGoChange(state) {
             let name = ''
             switch (state) {
                 case 'nickname':
@@ -173,7 +164,7 @@ export default {
         },
 
         // NOTE: 更新用户头像
-        handleUpdateAvatar () {
+        handleUpdateAvatar() {
             const params = {
                 type: 1,
                 avatar: this.updateAvatarImg
@@ -183,7 +174,7 @@ export default {
 
         async handleChooseLocalImg() {
             try {
-                const result = await getChooseImages({})    
+                const result = await getChooseImages({})
                 console.log('%c chooseimg res >>>', 'background: blue; color: #fff', result);
                 // TODO: Update image
                 const uploadResult = await upload(result.files)
@@ -197,10 +188,10 @@ export default {
 
         },
 
-        handleOpenCamera () {
+        handleOpenCamera() {
             this.handleChooseLocalImg()
         },
-        handleCancelPopup () {
+        handleCancelPopup() {
             this.show = false
         }
     }
@@ -209,7 +200,9 @@ export default {
 
 <style lang="less" scoped>
 @import url("@/styles/variables.less");
+
 .single-info {
+
     .infolist,
     .single-row {
         margin-top: 10px;
@@ -242,6 +235,7 @@ export default {
             font-weight: 400;
             color: #999999;
             line-height: 18px;
+
             img.avatar {
                 width: 32px;
                 height: 32px;
@@ -257,6 +251,7 @@ export default {
         }
 
     }
+
     .singlerrr {
         padding: 9px 17px 9px 12px;
 
@@ -273,6 +268,7 @@ export default {
                 margin: 0 auto;
             }
         }
+
         &-cancel {
             text-align: center;
             padding-bottom: 40px;
@@ -282,6 +278,7 @@ export default {
             line-height: 40px;
         }
     }
+
     .gap {
         height: 10px;
         background-color: @bg-gary;