瀏覽代碼

sop调试

刘洋 1 年之前
父節點
當前提交
dc09d30dc3

+ 2 - 0
src/api/sop.js

@@ -5,6 +5,8 @@ export const getSopList = (data) => http.post('/api/admin/sop/list', data, { cus
 export const getSopFlowView = (params) => http.post('/api/admin/flow/view', {}, { params, custom: { loading: true } })
 export const deviceCanOut = (params) => http.post('/api/admin/device/in/out/can_out_info', {}, { params })
 export const deviceCanIn = () => http.post('/api/admin/device/in/out/can_in_info')
+// sop填报-提交
+export const sopApproveApi = (data) => http.post('/api/admin/sop/approve', data, { custom: { loading: true } })
 
 // 项目计划变更 ------------------->
 // 项目计划变更列表

+ 1 - 1
src/api/user.js

@@ -4,7 +4,7 @@ import { getBase64 } from '@/utils/crypto'
 export const pcLogin = () =>
   http.post(
     '/api/admin/common/login',
-    { loginName: 'zhangjie', password: getBase64('123456'), type: 'ACCOUNT' },
+    { loginName: 'liuyang', password: getBase64('123456'), type: 'ACCOUNT' },
     {
       custom: { noAuth: true }
     }

+ 2 - 2
src/components/low-code/CHECKBOX.vue

@@ -7,7 +7,7 @@
 <script>
   export default {
     name: 'CHECKBOX',
-    props: ['config', 'onChange'],
+    props: ['config'],
     data() {
       return {
         options: [],
@@ -24,7 +24,7 @@
     },
     methods: {
       change(val) {
-        this.onChange({ prop: this.config.formName, value: val })
+        this.$emit('change', { prop: this.config.formName, value: val })
       }
     }
   }

+ 12 - 5
src/components/low-code/DATE.vue

@@ -1,15 +1,20 @@
 <template>
   <view>
-    <u-input v-model="value" type="select" :border="true" :disabled="!config.writable" @click="show = true" />
-    <!-- <u-select v-model="show" :list="options" @confirm="confirm"></u-select> -->
+    <u-input :value="valueStr" type="select" :border="true" :disabled="!config.writable" @click="show = true" />
     <u-calendar v-model="show" mode="date" @change="change"></u-calendar>
   </view>
 </template>
 
 <script>
+  import { dateFormat } from '@/utils/utils'
   export default {
     name: 'DATE',
-    props: ['config', 'onChange'],
+    props: ['config'],
+    computed: {
+      valueStr() {
+        return dateFormat(this.value, 'yyyy-MM-dd')
+      }
+    },
     data() {
       return {
         value: '',
@@ -21,8 +26,10 @@
     },
     methods: {
       change(obj) {
-        this.value = obj.result
-        // this.value = new Date(obj.result).getTime()
+        console.log('obj', obj)
+        // this.value = obj.result
+        this.value = new Date(obj.result).getTime()
+        this.$emit('change', { prop: this.config.formName, value: this.value })
       }
     }
   }

+ 9 - 1
src/components/low-code/DEVICE_IN_TABLE.vue

@@ -71,7 +71,15 @@
   export default {
     name: 'DEVICEINTABLE',
     components: { UPLOADIMAGE },
-    props: ['config', 'onChange'],
+    props: ['config'],
+    watch: {
+      value: {
+        handler(val) {
+          this.$emit('change', { prop: this.config.formName, value: val })
+        },
+        deep: true
+      }
+    },
     computed: {
       deviceStr() {
         return this.deviceList.find((item) => item.value == this.curDeviceInfo.deviceNo)?.label || ''

+ 9 - 1
src/components/low-code/DEVICE_OUT_TABLE.vue

@@ -81,7 +81,15 @@
   export default {
     name: 'DEVICEOUTTABLE',
     components: { UPLOADIMAGE },
-    props: ['config', 'onChange'],
+    props: ['config'],
+    watch: {
+      value: {
+        handler(val) {
+          this.$emit('change', { prop: this.config.formName, value: val })
+        },
+        deep: true
+      }
+    },
     computed: {
       deviceStr() {
         return this.deviceList.find((item) => item.value == this.curDeviceInfo.deviceNo)?.label || ''

+ 2 - 2
src/components/low-code/MULTIPLE_SELECT.vue

@@ -9,7 +9,7 @@
   import MultPicker from '@/components/mult-picker.vue'
   export default {
     name: 'MULTIPLESELECT',
-    props: ['config', 'onChange'],
+    props: ['config'],
     components: { MultPicker },
     data() {
       return {
@@ -24,7 +24,7 @@
     },
     methods: {
       confirm(obj) {
-        this.onChange({ prop: this.config.formName, value: obj.value })
+        this.$emit('change', { prop: this.config.formName, value: obj.value })
         this.value = obj.value
         this.show = false
       }

+ 2 - 2
src/components/low-code/RADIO.vue

@@ -9,7 +9,7 @@
 <script>
   export default {
     name: 'RADIO',
-    props: ['config', 'onChange'],
+    props: ['config'],
     data() {
       return {
         value: '',
@@ -22,7 +22,7 @@
     },
     methods: {
       change(val) {
-        this.onChange({ prop: this.config.formName, value: val })
+        this.$emit('change', { prop: this.config.formName, value: val })
       }
     }
   }

+ 2 - 2
src/components/low-code/RADIO_WITH_INPUT.vue

@@ -12,7 +12,7 @@
 <script>
   export default {
     name: 'RADIOWITHINPUT',
-    props: ['config', 'onChange'],
+    props: ['config'],
     data() {
       return {
         valueData: '',
@@ -27,7 +27,7 @@
     methods: {
       change(val) {
         console.log('va', val)
-        this.onChange({ prop: this.config.formName, value: val })
+        this.$emit('change', { prop: this.config.formName, value: val })
       }
     }
   }

+ 2 - 2
src/components/low-code/SELECT.vue

@@ -8,7 +8,7 @@
 <script>
   export default {
     name: 'SELECT',
-    props: ['config', 'onChange'],
+    props: ['config'],
     data() {
       return {
         value: '',
@@ -22,7 +22,7 @@
     },
     methods: {
       confirm(arr) {
-        this.onChange({ prop: this.config.formName, value: arr[0].value })
+        this.$emit('change', { prop: this.config.formName, value: arr[0].value })
         this.value = arr[0].value
       }
     }

+ 156 - 0
src/components/low-code/TABLE.vue

@@ -0,0 +1,156 @@
+<template>
+  <view class="device-in-table">
+    <view class="head flex justify-between items-center">
+      <view class="title">至少填写一行数据</view>
+      <u-button type="primary" plain @click="open" size="mini">新增</u-button>
+    </view>
+    <view class="list-box">
+      <view class="device-info-item" v-for="(item, index) in value" :key="index">
+        <view class="content">
+          <view class="item" v-for="v in config.tablePropList" :key="v.id">{{ v.title }}:{{ item[v.tdName] }}</view>
+        </view>
+        <view class="foot flex justify-end items-center">
+          <view class="btn-box flex items-center">
+            <u-button type="error" size="mini">删除</u-button>
+            <u-button type="primary" size="mini" class="m-l-10rpx" @click="edit(item)">编辑</u-button>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <u-popup v-model="showPopup" mode="bottom" :mask-close-able="false" :closeable="true" :border-radius="28">
+      <view class="form-box">
+        <view class="f-item" v-for="item in config.tablePropList" :key="item.id">
+          <view class="label">
+            <text class="red">*</text>
+            <text class="text">{{ item.title }}</text>
+          </view>
+          <u-input v-model="curInfo[item.tdName]" type="text" :border="true" placeholder="请输入" />
+        </view>
+
+        <view class="flex justify-between items-center p-b-50rpx">
+          <u-button class="flex-1" @click="showPopup = false">取消</u-button>
+          <u-button class="flex-1 m-l-30rpx" type="primary" @click="save">保存</u-button>
+        </view>
+      </view>
+    </u-popup>
+    <u-toast ref="uToast" />
+  </view>
+</template>
+
+<script>
+  export default {
+    name: 'TABLE',
+    props: ['config'],
+    watch: {
+      value: {
+        handler(val) {
+          this.$emit('change', { prop: this.config.formName, value: val })
+        },
+        deep: true
+      }
+    },
+    data() {
+      return {
+        list: [],
+        show: false,
+        showPopup: false,
+        value: [],
+        curInfo: {}
+      }
+    },
+    created() {
+      this.value = this.config.value || []
+      this.curInfo = this.config.tablePropList.reduce((obj, item) => {
+        obj[item.tdName] = ''
+        return obj
+      }, {})
+    },
+
+    methods: {
+      showError(txt) {
+        this.$refs.uToast.show({
+          title: txt,
+          type: 'error'
+        })
+      },
+      save() {
+        for (let key in this.curInfo) {
+          if (!this.curInfo[key]) {
+            const curColumn = this.config.tablePropList.find((item) => item.tdName == key)
+            return this.showError((curColumn?.title || '') + '不能为空')
+          }
+        }
+        this.value.push({ ...this.curInfo })
+        this.showPopup = false
+      },
+
+      edit(item) {
+        console.log('item', item)
+        this.curInfo = { ...item }
+        this.showPopup = true
+      },
+      open() {
+        for (let key in this.curInfo) {
+          this.curInfo[key] = ''
+        }
+        this.showPopup = true
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .device-in-table {
+    .list-box {
+      .device-info-item {
+        padding: 24rpx 0;
+        border-bottom: 1px solid #f0f0f0;
+        &:first-child {
+          padding-top: 0;
+        }
+        .foot {
+          margin-top: 10rpx;
+          .link {
+            color: $u-type-primary;
+            font-size: 28rpx;
+          }
+        }
+        .content {
+          background-color: #f7f7f7;
+          border-radius: 12rpx;
+          padding: 24rpx;
+          .item {
+            color: #262626;
+            font-size: 24rpx;
+            line-height: 60rpx;
+          }
+        }
+      }
+    }
+    .form-box {
+      padding: 24rpx 24px 0 24px;
+      padding-top: 80rpx;
+      .f-item {
+        margin-bottom: 30rpx;
+        .label {
+          margin-bottom: 4rpx;
+          .red {
+            color: red;
+            margin-right: 4rpx;
+          }
+          .text {
+            color: #595959;
+          }
+        }
+      }
+    }
+    .head {
+      .title {
+        color: #595959;
+        font-size: 28rpx;
+        height: 60rpx;
+      }
+    }
+  }
+</style>

+ 2 - 2
src/components/low-code/TEXT.vue

@@ -5,7 +5,7 @@
 <script>
   export default {
     name: 'TEXT',
-    props: ['config', 'onChange', 'type'],
+    props: ['config', 'type'],
     data() {
       return {
         value: ''
@@ -16,7 +16,7 @@
     },
     methods: {
       onInput() {
-        this.onChange({ prop: this.config.formName, value: this.value })
+        this.$emit('change', { prop: this.config.formName, value: this.value })
       }
     }
   }

+ 54 - 28
src/components/low-code/UPLOAD_IMAGE.vue

@@ -9,7 +9,8 @@
       :action="action"
       :header="header"
       :form-data="{ type: 'FILE' }"
-      @on-list-change="change"
+      @on-success="successChange"
+      @on-remove="removeChange"
     ></u-upload>
     <view class="tip">最多只能上传 {{ config.length || 3 }}张图片</view>
   </view>
@@ -19,7 +20,7 @@
   import SparkMD5 from 'spark-md5'
   import { getAuthorization, DEVICE_ID } from '@/utils/crypto'
   export default {
-    props: ['config', 'onChange'],
+    props: ['config'],
     data() {
       return {
         fileList: [],
@@ -27,7 +28,7 @@
         md5: '',
         header: {
           'Content-Type': 'multipart/form-data',
-          md5: '92eeda52d99adc1e4640520e20bda65f',
+          md5: '',
           deviceId: DEVICE_ID,
           platform: 'WEB',
           Authorization: '',
@@ -39,10 +40,12 @@
       this.fileList = this.config.value || []
     },
     watch: {
-      'config.value'(value) {
-        console.log('watch', value)
-        this.$refs.uUpload?.clear()
-        this.fileList = value || []
+      'config.value': {
+        handler(value) {
+          this.$refs.uUpload?.clear()
+          this.fileList = value || []
+        },
+        deep: true
       }
     },
     methods: {
@@ -51,30 +54,53 @@
       //     let decoder = new TextDecoder(decodeType)
       //     return decoder.decode(buffer)
       //   },
+      removeChange(index, lists, name) {
+        let imgList = lists.map((item) => {
+          return { ...item.response.data, url: item.response.data.previewUrl }
+        })
 
-      change(lists) {
-        console.log('lll', lists)
-        //非常蛋疼,这个change事件里的回调里提供的参数lists里,并不会立刻包含response属性,会有延迟!于是使用了一个定时器!
-        setTimeout(() => {
-          //上传图片,删除图片会触发该方法,同样从父组件改变config的value值也会触发watch也会触发这里的change方法,通过lists里有没有file属性来判断
-          let imgList =
-            lists.length && lists[0].file
-              ? lists.map((item) => {
-                  return { ...item.response.data, url: item.response.data.previewUrl }
-                })
-              : lists
+        this.$emit('change', {
+          prop: this.config.formName,
+          value: imgList
+        })
+      },
+      successChange(data, index, lists, name) {
+        //上传图片,删除图片会触发该方法,同样从父组件改变config的value值也会触发watch也会触发这里的change方法,通过lists里有没有file属性来判断
+        let imgList = lists.map((item) => {
+          return { ...item.response.data, url: item.response.data.previewUrl }
+        })
 
-          //该组件兼容动态表单使用和常规业务使用,通过config参数里是否有formName来区分
-          if (this.config.formName) {
-            this.onChange({
-              prop: this.config.formName,
-              value: imgList
-            })
-          } else {
-            this.$emit('getLists', imgList)
-          }
-        }, 250)
+        //该组件兼容动态表单使用和常规业务使用,通过config参数里是否有formName来区分
+        // if (this.config.formName) {
+        this.$emit('change', {
+          prop: this.config.formName,
+          value: imgList
+        })
+        // } else {
+        //   this.$emit('getLists', imgList)
+        // }
       },
+      // change(lists) {
+      //   //非常蛋疼,这个change事件里的回调里提供的参数lists里,并不会立刻包含response属性,会有延迟!于是使用了一个定时器!
+      //   setTimeout(() => {
+      //     //上传图片,删除图片会触发该方法,同样从父组件改变config的value值也会触发watch也会触发这里的change方法,通过lists里有没有file属性来判断
+      //     // let imgList =
+      //     //   lists.length && lists[0].file
+      //     //     ? lists.map((item) => {
+      //     //         return { ...item.response.data, url: item.response.data.previewUrl }
+      //     //       })
+      //     //     : lists
+      //     // //该组件兼容动态表单使用和常规业务使用,通过config参数里是否有formName来区分
+      //     // if (this.config.formName) {
+      //     //   this.$emit('change', {
+      //     //     prop: this.config.formName,
+      //     //     value: imgList
+      //     //   })
+      //     // } else {
+      //     //   this.$emit('getLists', imgList)
+      //     // }
+      //   }, 400)
+      // },
       beforeUpload(index, list) {
         console.log('beforeUpload:')
         const _this = this

+ 22 - 15
src/components/low-code/my-form-item.vue

@@ -2,20 +2,22 @@
   <u-form-item class="my-form-item" label=" " label-width="1rpx" :border-bottom="false" :prop="config.formName">
     <view>
       <view class="top-label flex items-center" :class="{ 'm-t-40rpx m-b-30rpx': isBigTitle }">
+        <text class="red" v-if="!isBigTitle && config.required">*</text>
         <text>{{ config.title }}</text>
       </view>
-      <!-- <TEXT :config="config" :onChange="onChange" type="text"></TEXT> -->
-      <!-- <SELECT :config="config" :onChange="onChange"></SELECT> -->
-      <!-- <MULTIPLESELECT :config="config" :onChange="onChange"></MULTIPLESELECT> -->
-      <!-- <DATE :config="config" :onChange="onChange"></DATE> -->
-      <!-- <RADIO :config="config" :onChange="onChange"></RADIO> -->
-      <!-- <CHECKBOX :config="config" :onChange="onChange"></CHECKBOX> -->
-      <!-- <TEXT :config="config" :onChange="onChange" type="textarea"></TEXT> -->
-      <!-- <TEXT :config="config" :onChange="onChange" type="number"></TEXT> -->
-      <!-- <UPLOADIMAGE :config="config" :onChange="onChange"></UPLOADIMAGE> -->
-      <!-- <RADIOWITHINPUT :config="config" :onChange="onChange"></RADIOWITHINPUT> -->
-      <!-- <DEVICEINTABLE :config="config" :onChange="onChange"></DEVICEINTABLE> -->
-      <DEVICEOUTTABLE :config="config" :onChange="onChange"></DEVICEOUTTABLE>
+      <TEXT v-if="config.code === 'TEXT'" :config="config" @change="change" type="text"></TEXT>
+      <SELECT v-if="config.code === 'SELECT'" :config="config" @change="change"></SELECT>
+      <MULTIPLESELECT v-if="config.code === 'MULTIPLE_SELECT'" :config="config" @change="change"></MULTIPLESELECT>
+      <DATE v-if="config.code === 'DATE'" :config="config" @change="change"></DATE>
+      <RADIO v-if="config.code === 'RADIO'" :config="config" @change="change"></RADIO>
+      <CHECKBOX v-if="config.code === 'CHECKBOX'" :config="config" @change="change"></CHECKBOX>
+      <TEXT v-if="config.code === 'TEXTAREA'" :config="config" @change="change" type="textarea"></TEXT>
+      <TEXT v-if="config.code === 'NUMBER'" :config="config" @change="change" type="number"></TEXT>
+      <UPLOADIMAGE v-if="config.code === 'FILE'" :config="config" @change="change"></UPLOADIMAGE>
+      <RADIOWITHINPUT v-if="config.code === 'RADIO_WITH_INPUT'" :config="config" @change="change"></RADIOWITHINPUT>
+      <DEVICEINTABLE v-if="config.code === 'DEVICE_IN_TABLE'" :config="config" @change="change"></DEVICEINTABLE>
+      <DEVICEOUTTABLE v-if="config.code === 'DEVICE_OUT_TABLE'" :config="config" @change="change"></DEVICEOUTTABLE>
+      <TABLE v-if="config.code === 'TABLE'" :config="config" @change="change"></TABLE>
     </view>
   </u-form-item>
 </template>
@@ -31,10 +33,11 @@
   import RADIOWITHINPUT from './RADIO_WITH_INPUT.vue'
   import DEVICEINTABLE from './DEVICE_IN_TABLE.vue'
   import DEVICEOUTTABLE from './DEVICE_OUT_TABLE.vue'
+  import TABLE from './TABLE.vue'
   export default {
     name: 'MyFormItem',
-    props: ['config'],
-    components: { TEXT, SELECT, MULTIPLESELECT, DATE, RADIO, CHECKBOX, UPLOADIMAGE, RADIOWITHINPUT, DEVICEINTABLE, DEVICEOUTTABLE },
+    props: ['config', 'change1', 'change2'],
+    components: { TEXT, SELECT, MULTIPLESELECT, DATE, RADIO, CHECKBOX, UPLOADIMAGE, RADIOWITHINPUT, DEVICEINTABLE, DEVICEOUTTABLE, TABLE },
     computed: {
       isBigTitle() {
         return this.bigTitles.includes(this.config.code)
@@ -46,7 +49,7 @@
       }
     },
     methods: {
-      onChange(obj) {
+      change(obj) {
         this.$emit('change', obj)
       }
     }
@@ -60,6 +63,10 @@
       font-size: 28rpx;
       line-height: 60rpx;
       font-weight: bold;
+      .red {
+        color: red;
+        margin-right: 8rpx;
+      }
     }
   }
 </style>

+ 121 - 16
src/pages/sop-step/sop-step.vue

@@ -1,18 +1,22 @@
 <template>
   <view class="sop-step">
     <u-tabs :list="tabs" :is-scroll="true" :current="current" @change="tabChange"></u-tabs>
-    <scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y">
+    <scroll-view scroll-y="true" class="scroll-Y">
       <view class="main">
         <!-- <u-button class="premission-button" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">授权登录</u-button> -->
         <RadiusCell title="SOP各协作项目角色说明" @click="showPopup1 = true"></RadiusCell>
         <RadiusCell title="项目派单信息" @click="showPopup2 = true"></RadiusCell>
         <view class="form-wrap">
-          <u-form :model="formData" ref="form">
+          <u-form :model="formData" ref="uForm">
             <MyFormItem :config="config" @change="itemValueChange" v-for="config in curFormConfig" :key="config.formName"></MyFormItem>
           </u-form>
         </view>
       </view>
     </scroll-view>
+    <view class="bottom-btns flex justify-between items-center">
+      <u-button :disabled="current + 1 !== setup" class="flex-1" @click="submit('DRAFT')">保存草稿</u-button>
+      <u-button :disabled="current + 1 !== setup" class="flex-1 m-l-30rpx" type="primary" @click="submit('START')">提交</u-button>
+    </view>
 
     <u-popup v-model="showPopup1" mode="bottom" :mask-close-able="false" :closeable="true" :border-radius="28">
       <view class="popup-box1">
@@ -48,15 +52,17 @@
         </view>
       </view>
     </u-popup>
+    <u-toast ref="uToast" />
   </view>
 </template>
 
 <script>
   import RadiusCell from '@/components/radius-cell.vue'
-  import { getSopFlowView } from '@/api/sop'
+  import { getSopFlowView, sopApproveApi } from '@/api/sop'
   import { CUSTOMER_TYPE } from '@/utils/constants'
   import testData from './test'
   import MyFormItem from '@/components/low-code/my-form-item.vue'
+  import { cloneDeep } from 'lodash-es'
   const needValueCodes = [
     'NUMBER', //新增
     'TEXT',
@@ -73,6 +79,7 @@
     'FILE'
   ]
   const fullWidthCodes = ['TABLE', 'FORM_GROUP_TITLE', 'TEXTAREA', 'ONLY_TITLE', 'DEVICE_OUT_TABLE', 'DEVICE_IN_TABLE']
+  const arrayValueCodes = ['TABLE', 'DEVICE_OUT_TABLE', 'DEVICE_IN_TABLE', 'MULTIPLE_SELECT', 'CHECKBOX', 'FILE']
   export default {
     name: 'SopStep',
     components: { RadiusCell, MyFormItem },
@@ -81,18 +88,32 @@
         CUSTOMER_TYPE,
         showPopup1: false,
         showPopup2: false,
-        flowId: '433300909770932224',
+        flowId: '',
+        taskId: '',
         current: 0,
         allSteps: [], //流程步骤数组全数据
         tabs: [],
         crmInfo: {},
         formData: {},
-        rules: {}
+        rules: {},
+        setup: 0
       }
     },
     computed: {
       curFormConfig() {
-        const formProperty = this.allSteps[this.current]?.formProperty || []
+        const formProperty = (this.allSteps[this.current]?.formProperty || []).map((item) => {
+          if (item.value && typeof item.value === 'string') {
+            try {
+              item.value = JSON.parse(item.value).value
+            } catch {
+              console.log('这个value值不能被JSON.parse解析,估计之前提交的时候没有用value包一层:', item.value)
+            }
+          }
+          if (item.options && typeof item.options === 'string') {
+            item.options = JSON.parse(item.options)
+          }
+          return item
+        })
         return formProperty
       }
     },
@@ -100,18 +121,35 @@
       curFormConfig(val) {
         this.formData = val.reduce((obj, item) => {
           if (needValueCodes.includes(item.code)) {
-            obj[item.formName] = ''
+            obj[item.formName] = item.value || ''
           }
           return obj
         }, {})
         this.rules = val.reduce((obj, item) => {
+          let ruleMap = {
+            DATE: {
+              validator: (rule, value, callback) => {
+                return this.$u.test.number(value)
+              }
+            },
+            ARRAY: {
+              validator: (rule, value, callback) => {
+                return Array.isArray(value) && value.length
+              },
+              message: item.code === 'FILE' ? '请上传图片' : '请至少填写一项'
+            }
+          }
+          let extentsRule = ruleMap[arrayValueCodes.includes(item.code) ? 'ARRAY' : item.code] || { required: true }
           let ruleItem =
             item.required && needValueCodes.includes(item.code)
-              ? {
-                  required: true,
-                  message: `${item.title}不能为空`,
-                  trigger: 'change'
-                }
+              ? Object.assign(
+                  {},
+                  {
+                    message: `${item.title}不能为空`,
+                    trigger: 'change'
+                  },
+                  extentsRule
+                )
               : null
           if (ruleItem) {
             obj[item.formName] = [ruleItem]
@@ -124,6 +162,60 @@
       }
     },
     methods: {
+      submit(approve = 'START') {
+        // const formProperties = cloneDeep(this.curFormConfig)
+        // const formPropertiesValueJsonWithValueKey = formProperties.map((item) => {
+        //   item.value = JSON.stringify({ value: this.formData[item.formName] })
+        //   if (Array.isArray(item.options)) {
+        //     item.options = JSON.stringify(item.options)
+        //   }
+        //   return item
+        // })
+        // console.log('formPropertiesValueJsonWithValueKey:', formPropertiesValueJsonWithValueKey)
+        // sopApproveApi({
+        //   taskId: this.taskId,
+        //   formProperties: formPropertiesValueJsonWithValueKey,
+        //   setup: this.setup,
+        //   approve
+        // }).then(() => {
+        //   this.$refs.uToast.show({
+        //     title: '填报成功',
+        //     type: 'success'
+        //   })
+        //   this.$Router.back()
+        // })
+        // console.log('rrr', this.rules)
+        this.$refs.uForm.validate((valid) => {
+          if (valid) {
+            console.log('验证通过')
+            console.log('valid:', valid)
+            const formProperties = cloneDeep(this.curFormConfig)
+            const formPropertiesValueJsonWithValueKey = formProperties.map((item) => {
+              item.value = JSON.stringify({ value: this.formData[item.formName] })
+              if (Array.isArray(item.options)) {
+                item.options = JSON.stringify(item.options)
+              }
+              return item
+            })
+            console.log('formPropertiesValueJsonWithValueKey:', formPropertiesValueJsonWithValueKey)
+            sopApproveApi({
+              taskId: this.taskId,
+              formProperties: formPropertiesValueJsonWithValueKey,
+              setup: this.setup,
+              approve
+            }).then(() => {
+              this.$refs.uToast.show({
+                title: '填报成功',
+                type: 'success'
+              })
+              this.$Router.back()
+            })
+          } else {
+            console.log('this.formData:', this.formData)
+            console.log('验证失败')
+          }
+        })
+      },
       getPhoneNumber(e) {
         console.log('eee', e)
       },
@@ -132,8 +224,9 @@
       },
       init() {
         getSopFlowView({ flowId: this.flowId }).then((res) => {
-          res = { crmInfo: res.crmInfo, ...testData }
+          // res = { crmInfo: res.crmInfo, ...testData }
           this.crmInfo = res.crmInfo || {}
+          this.setup = res.currFlowTaskResult?.setup
           res.flowTaskHistoryList = res.flowTaskHistoryList || []
           res.flowTaskHistoryList.forEach((item) => {
             item.formProperty.forEach((v) => {
@@ -150,15 +243,17 @@
             }
           ]
           this.current = this.tabs.length - 1
+          console.log(this.current, this.setup)
         })
       },
       itemValueChange({ prop, value }) {
         console.log(prop, ':', value)
-        this.formData[prop] = value
+        this.formData[prop] = Array.isArray(value) ? [...value] : value
       }
     },
     mounted() {
-      console.log('query', this.$Route.query)
+      this.flowId = this.$Route.query.flowId
+      this.taskId = this.$Route.query.taskId
       this.init()
     }
   }
@@ -167,8 +262,18 @@
 <style lang="scss" scoped>
   .sop-step {
     height: 100vh;
+    .bottom-btns {
+      border: 1px solid #d9d9d9;
+      padding: 12rpx 24rpx 50rpx 24rpx;
+      background: #fff;
+      position: fixed;
+      width: 100vw;
+      bottom: 0;
+      left: 0;
+      z-index: 100;
+    }
     .scroll-Y {
-      height: calc(100% - 88rpx);
+      height: calc(100% - 230rpx);
       .main {
         padding: 24rpx;
         .form-wrap {

+ 64 - 2
src/pages/sop-step/test.js

@@ -28,8 +28,70 @@ export default {
     formKey: 'XXX',
     formProperty: [
       {
-        code: 'DEVICE_OUT_TABLE',
-        title: '设备出库登记'
+        code: 'TABLE',
+        title: '这是一个TABLE组件',
+        tablePropList: [
+          {
+            id: 'XXX1',
+            widgetId: 'XXX',
+            tdIndex: 1,
+            tdId: 'XXX',
+            tdName: 'XXX1',
+            title: '学院/分(子)机构',
+            tdOrder: true,
+            tdSearch: true,
+            editWidgetId: '19',
+            tdFormWidget: {
+              code: 'TEXT',
+              name: '文本'
+            }
+          },
+          {
+            id: 'XXX2',
+            widgetId: 'XXX',
+            tdIndex: 2,
+            tdId: 'XXX2',
+            tdName: 'XXX2',
+            title: '姓名',
+            tdOrder: true,
+            tdSearch: true,
+            editWidgetId: 'XXX',
+            tdFormWidget: {
+              code: 'TEXT',
+              name: '文本'
+            }
+          },
+          {
+            id: 'XXX3',
+            widgetId: 'XXX',
+            tdIndex: 3,
+            tdId: 'XXX',
+            tdName: 'XXX3',
+            title: '职务',
+            tdOrder: true,
+            tdSearch: true,
+            editWidgetId: 'XXX',
+            tdFormWidget: {
+              code: 'TEXT',
+              name: '文本'
+            }
+          },
+          {
+            id: 'XXX4',
+            widgetId: 'XXX',
+            tdIndex: 4,
+            tdId: 'XXX',
+            tdName: 'XXX4',
+            title: '手机',
+            tdOrder: true,
+            tdSearch: true,
+            editWidgetId: 'XXX',
+            tdFormWidget: {
+              code: 'TEXT',
+              name: '文本'
+            }
+          }
+        ]
       }
       // {
       //   code: 'RADIO',

+ 1 - 3
src/pages/sop/office-sop-list.vue

@@ -1,7 +1,6 @@
 <template>
   <view class="office-sop-list flex flex-col">
     <scroll-view
-      :scroll-top="scrollTop"
       scroll-y="true"
       refresher-enabled="true"
       class="scroll-Y"
@@ -63,8 +62,7 @@
     },
     methods: {
       toCurSopFlow(item) {
-        console.log('iii', item)
-        this.$Router.push({ path: '/pages/sop-step/sop-step' })
+        this.$Router.push({ path: '/pages/sop-step/sop-step', query: { flowId: item.flowId, taskId: item.taskId } })
       },
       scrolltolower() {
         if (this.loadingFlag > 0) {