Browse Source

Merge branch 'main'

xiaodai2017 1 year ago
parent
commit
fc64e0f345

+ 3 - 1
src/apis/components/search.js

@@ -2,8 +2,10 @@ import http from "@/apis/axios";
 
 export default {
     store: (data, params) => http("admin/supplierStore/index", data, "post", params),
-    customer: (data, params) => http("admin/customer/query", data, "post", params),
+    customer: (data, params) => http("admin/customer/list", data, "post", params),
     demand: (data, params) => http("admin/service_item/index", data, "post", params),
     addr: (data, params) => http("admin/login/area", data, "post", params),
     title: (data, params) => http("admin/invoiceTitle/index", data, "post", params),
+    actType: (data, params) => http("admin/activityCat/index", data, "post", params),
+    peoNum: (data, params) => http("admin/attendance/index", data, "post", params),
 };

+ 1 - 0
src/apis/service/customerService/workbench/index.js

@@ -19,6 +19,7 @@ export default {
   planStatus:(data, params) => http(planAPI + 'status', data, 'post', params),
   planDetail:(data, params) => http(planAPI + 'info', data, 'post', params),
   planDelete:(data, params) => http(planAPI + 'deleteinfo', data, 'post', params),
+  planUpdate:(data, params) => http(planAPI + 'save', data, 'post', params),
 
   // 采返商品详情
   good_detail: (data, params) =>

+ 60 - 22
src/components/manage/src/letter/index.vue

@@ -1,8 +1,6 @@
 <template>
   <div>
-
     <div style="display:flex;justify-content:flex-end" v-if="!readonly">
-      <el-button size="mini" @click="linkToLetterUpdate" v-if="type === 'project'">编辑预算函</el-button>
       <el-button size="mini" @click="onDownloadTemplate">下载{{mapTitle[type]}}模板</el-button>
       <el-button size="mini" type="primary" @click="handleUploadModalVisible">上传{{mapTitle[type]}}</el-button>
     </div>
@@ -11,6 +9,19 @@
         ...(isSelection ? [{ type: 'selection' }] : []),
         ...mapColumns[type || 'budget'], { label: '操作', _slot_: 'action', width: '100px',fixed:'right'}
       ]"
+      @page-curr-change="handlePageChange"
+      @page-size-change="handleSizeChange"
+      :page="pageInfo"
+      @screen-reset="
+        pageInfo.curr = 1;
+        parmValue.page = 1;
+        searchList();
+      "
+      @screen-submit="
+        pageInfo.curr = 1;
+        parmValue.page = 1;
+        searchList();
+        "
       @selection="handleSelection"
       :table="table"
       :data="tableData"
@@ -21,13 +32,12 @@
          {{ Number(scope.row.is_check) === mapCheck[type || 'budget'].ok  ?  "已选择" : "未选择" }}
         </el-tag>
       </template>
-
-      <!-- <template #letter="{}">
-        <a href="http://hwpro.test241.wanyuhengtong.com/storage/default/20230608/6916c8847df2d1ee629c3490fe43501003ef1e7a.xlsx">{{getFileNameWithUrl('http://hwpro.test241.wanyuhengtong.com/storage/default/20230608/6916c8847df2d1ee629c3490fe43501003ef1e7a.xlsx')}}</a>
-      </template> -->
-      
       <template #action="{ scope }">
-        <el-button type="text" size="mini" @click="openModal(scope.row)">查看</el-button>
+        <el-button 
+          v-if="type === 'budget' && Number(scope.row.is_check) !== mapCheck[type].ok" type="text" 
+          size="mini" 
+          @click="linkToLetterUpdate(scope.row)"
+        >编辑</el-button>
         <el-button 
           v-if="type === 'budget' && Number(scope.row.is_check) !== mapCheck[type].ok" 
           type="text" 
@@ -41,7 +51,7 @@
       :requsetMethod="requsetMethod"
       :visible.sync="xlsxVisible"
       @submit="handleSubmit"
-      @refresh="onSearch"
+      @refresh="refresh"
       :isFile="isFile"
       :title="title" 
       :type="type"
@@ -62,9 +72,11 @@ import asyncRequest from "@/apis/components/letter"
 import PreviewModal from "./previewModal.vue"
 import { writeFile, utils } from "xlsx";
 import { template } from "./_template"
+import mixinPage from "@/mixins/elPaginationHandle";
 
 export default {
   name:'Letter',
+  mixins:[mixinPage],
   /* type:budget预算函 activity活动方案 project计划 **/
   props:['title', 'requsetMethod', 'status', 'id', 'isSelection', 'readonly','type', 'beforeModalVisible', 'isFile'],
   components:{ ExcelUploadModal, PreviewModal },
@@ -75,6 +87,15 @@ export default {
         border: true,
         'max-height': '800px'
       },
+      parmValue:{
+        page: 1, // 页码
+        size: 15, // 每页显示条数
+      },
+      pageInfo: {
+        size: 15,
+        curr: 1,
+        total: 0,
+      },
       sitem: {},
       mapCheck,
       mapTitle,
@@ -84,20 +105,32 @@ export default {
       previewVisible:false
     }
   },
-  mounted(){
-    this.onSearch()
+  watch:{
+    id(val){
+      if(!val) return
+      this.searchList()
+    }
   },
+  // mounted(){
+    // this.searchList()
+  // },
   methods:{
+    refresh(){
+      this.searchList()
+      this.$emit('refresh')
+    },
     handleSelection({list}){
       this.$emit('selection', list.map(({id}) => id))
     },
     deleteItem(row){
-      this.$confirm("确认删除?").then(async () => {
+      this.$confirm(`确认删除评估预算函 ${row.planCode}?`,{
+        type:'warning'
+      }).then(async () => {
         this.loading = true
         const { code } = await asyncRequest.delete({id:row.id})
         this.loading = false
         if(code !== 1) return
-        this.onSearch()
+        this.searchList()
       })
     },
     openModal(row){
@@ -112,6 +145,9 @@ export default {
         bookType:'xlsx'
       })
     },
+    linkToLetterUpdate(row){
+      this.$router.push('/customerService/letterEditing?id=' + row.id)
+    },
     getFileNameWithUrl(url){
       const chunks = url.split('/')
       const fullFileName = chunks[chunks.length - 1]
@@ -125,20 +161,22 @@ export default {
 
       this.xlsxVisible = true
     },
-    linkToLetterUpdate(){
-      if(this.beforeModalVisible && !this.beforeModalVisible()){
-        return
-      }
-
-      this.$emit('updateLetter')
-    },
-    async onSearch(){
+    // linkToLetterUpdate(){
+    //   // if(this.beforeModalVisible && !this.beforeModalVisible()){
+    //   //   return
+    //   // }
+    //   this.$emit('updateLetter')
+    // },
+    async searchList(){
       if(this.type === 'settlement') return
       this.loading = true
-      const { code, data } = await asyncRequest.list({ status:this.status, req_id: this.id })
+      const { code, data } = await asyncRequest.list({ status:this.status, req_id: this.id ,...this.parmValue})
       this.loading = false
       if(code !== 1) return
       this.tableData = data.list
+      this.pageInfo.total = Number(data.count)
+
+      console.log(this.pageInfo)
     }
   }
 }

+ 17 - 1
src/components/manage/src/letter/xlsxUploadModal.vue

@@ -30,6 +30,12 @@
       </div>
     </div>
 
+    <div style="display:flex;align-items:center;margin:10px 0px" v-if="type === 'budget'">
+      <p style="margin-right:10px">店铺:</p>
+      <search-store size="mini" :value.sync="storeId" />
+    </div>
+         
+
     <div style="padding:10px" v-loading="loading">
      <div v-if="tableData && tableData.length > 0" class="tr" style="padding: 10px 0 0 0">
       <el-button :size="'mini'" @click="() => tableData = []">取消</el-button>
@@ -42,6 +48,7 @@
       </div>
 
       <ex-table
+        noPagination
         :columns="columns"
         :table="table"
         :data="tableData"
@@ -74,6 +81,7 @@ export default {
       columns,
       loading: false,
       tableData: [],
+      storeId:"",
       file_url:"",
       isInit:true,
       mapTitle,
@@ -220,12 +228,20 @@ export default {
         this.$message.warning('请上传文件!')
         return
       }
+
+      if(this.type === "budget" && !this.storeId){
+        this.$message.warning('请选择店铺!')
+        return
+      }
+
+
       const planinfo = this.tableData.map(tableItem => requsetFields.reduce((prev, currentKey) => ({
         ...prev,
         [currentKey]: tableItem[currentKey]
       }), {}))
+
       this.loading = true
-      const { code } = await this.requsetMethod(planinfo, this.file_url)
+      const { code } = await this.requsetMethod(planinfo, this.file_url, this.storeId)
       this.loading = false
       if(code !== 1) return
       this.$emit('refresh')

+ 7 - 1
src/components/search/index.js

@@ -2,12 +2,18 @@ import SearchStore from "./src/store.vue"
 import SearchCustomer from "./src/customer.vue"
 import SearchDemand from "./src/demand.vue"
 import SearchTitle from "./src/title.vue"
+import SearchActivityType from "./src/activity-type"
+import SearchPeopleNumber from "./src/people-number"
+import SearchAddr from "./src/addr"
 
 const searchComponents = [
   SearchStore,
   SearchCustomer,
   SearchDemand,
-  SearchTitle
+  SearchTitle,
+  SearchActivityType,
+  SearchAddr,
+  SearchPeopleNumber
 ]
 
 export default searchComponents

+ 54 - 0
src/components/search/src/activity-type.vue

@@ -0,0 +1,54 @@
+<template>
+  <el-select
+    v-model="_value"
+    :size="size" 
+    remote
+    :remote-method="onFetch"
+    :placeholder="placeholder || '请选择客户公司'"
+    :loading="loading"
+    reserve-keyword
+    filterable
+    clearable
+  >
+    <el-option 
+      v-for="item in list" 
+      :key="item.id" 
+      :value="item.id" 
+      :label="item.name"
+    />
+  </el-select>
+</template>
+
+
+<script>
+import asyncRequest from "@/apis/components/search"
+export default {
+  name:'SearchActivityType',
+  props:['size', 'value' , 'placeholder', 'level'],
+  data(){
+    return {
+      loading: false,
+      list: []
+    }
+  },
+  computed:{
+    _value:{
+        get(){
+          return this.value
+        },
+        set(newVal){
+          const current = this.list.find(({id}) => id === newVal)
+          this.$emit('change', current)
+          this.$emit('update:value', newVal)
+        }
+    }
+  },
+  methods:{
+    async onFetch(keyword = ""){
+      const {code, data} = await asyncRequest.actType({ name: keyword })
+      if(code !== 1) return
+      this.list = data.list
+    }
+  }
+}
+</script>

+ 5 - 5
src/components/search/src/addr.vue

@@ -4,7 +4,7 @@
     :size="size" 
     remote
     :remote-method="onFetch"
-    :placeholder="placeholder || '请选择客户公司'"
+    :placeholder="placeholder || '请选择城市'"
     :loading="loading"
     reserve-keyword
     filterable
@@ -12,9 +12,9 @@
   >
     <el-option 
       v-for="item in list" 
-      :key="item.id" 
-      :value="item.id" 
-      :label="item.store_name"
+      :key="item.value" 
+      :value="item.value" 
+      :label="item.label"
     />
   </el-select>
 </template>
@@ -23,7 +23,7 @@
 <script>
 import asyncRequest from "@/apis/components/search"
 export default {
-  name:'SearchCustomer',
+  name:'SearchAddr',
   props:['size', 'value' , 'placeholder', 'level'],
   data(){
     return {

+ 2 - 2
src/components/search/src/customer.vue

@@ -10,7 +10,7 @@
     filterable
     clearable
   >
-    <el-option v-for="item in list" :key="item.id" :value="item.id" :label="item.store_name" />
+    <el-option v-for="item in list" :key="item.id" :value="item.id" :label="item.companyName" />
   </el-select>
 </template>
 
@@ -42,7 +42,7 @@ export default {
     async onFetch(keyword){
       const {code, data} = await asyncRequest.customer({companyName: keyword})
       if(code !== 1) return
-      this.list = data
+      this.list = data.list
     }
   }
 }

+ 54 - 0
src/components/search/src/people-number.vue

@@ -0,0 +1,54 @@
+<template>
+  <el-select
+    v-model="_value"
+    :size="size" 
+    remote
+    :remote-method="onFetch"
+    :placeholder="placeholder || '活动人数'"
+    :loading="loading"
+    reserve-keyword
+    filterable
+    clearable
+  >
+    <el-option 
+      v-for="item in list" 
+      :key="item.id" 
+      :value="item.id" 
+      :label="item.name"
+    />
+  </el-select>
+</template>
+
+
+<script>
+import asyncRequest from "@/apis/components/search"
+export default {
+  name:'SearchPeopleNumber',
+  props:['size', 'value' , 'placeholder', 'level'],
+  data(){
+    return {
+      loading: false,
+      list: []
+    }
+  },
+  computed:{
+    _value:{
+        get(){
+          return this.value
+        },
+        set(newVal){
+          const current = this.list.find(({id}) => id === newVal)
+          this.$emit('change', current)
+          this.$emit('update:value', newVal)
+        }
+    }
+  },
+  methods:{
+    async onFetch(keyword = ""){
+      const {code, data} = await asyncRequest.peoNum({ name: keyword })
+      if(code !== 1) return
+      this.list = data.list
+    }
+  }
+}
+</script>

+ 9 - 9
src/views/customerService/demandOrder/components/waitExecuteCertificate.vue

@@ -7,7 +7,7 @@
       </el-form-item>
 
       <el-form-item label="客户公司" prop="customer_id">
-        <search-customer :data.sync="ruleForm.customer_id" style="width:500px" />
+        <search-customer :value.sync="ruleForm.customer_id" style="width:500px" />
       </el-form-item>
 
       <el-form-item label="审核备注" prop="remark">
@@ -45,13 +45,13 @@ export default {
   computed:{
     rules(){
       return {
-      // customer_id:[
-      //   {
-      //     required:true,
-      //     trigger:'change',
-      //     message:'请选择客户公司'
-      //   }
-      // ],
+      customer_id:[
+        {
+          required:this.ruleForm.status !== '8',
+          trigger:'change',
+          message:'请选择客户公司'
+        }
+      ],
       status:[
         {
           required:true,
@@ -77,7 +77,7 @@ export default {
             this.loading = true
             const { code } = await asyncRequest.status({
               id: this.sitem.id,
-              customer_id : "1",
+              customer_id,
               status,
               remark
             })

+ 13 - 24
src/views/customerService/demandOrder/index.vue

@@ -37,14 +37,12 @@
                 />
               </el-col>
 
-              <el-col :span="4" style="width:200px">
-                <el-select v-model="parmValue.city" size="mini" placeholder="活动城市" @change="
-                pageInfo.curr = 1;
-                parmValue.page = 1;
-                searchList();
-               ">
-                  <el-option />
-                </el-select>
+              <el-col :span="4">
+                <search-people-number style="width:100%" size="mini" :data.sync="parmValue.activityPerson" placeholder="活动人数"  @change="
+                  pageInfo.curr = 1;
+                  parmValue.page = 1;
+                  searchList();
+                " />
               </el-col>
                             
               <el-col :span="3" style="width: 66px; float: right">
@@ -96,14 +94,7 @@
               </el-col>
 
               <el-col :span="4">
-                <!-- <el-select  v-model="parmValue.activityDemand" style="width:100%" size="mini" placeholder="活动需求" @change="
-                pageInfo.curr = 1;
-                parmValue.page = 1;
-                searchList();
-               ">
-                  <el-option />
-                </el-select> -->
-                <search-demand size="mini" :value.sync="parmValue.activityDemand"  @change="
+                <search-demand style="width:100%" size="mini" :value.sync="parmValue.activityDemand"  @change="
                   pageInfo.curr = 1;
                   parmValue.page = 1;
                   searchList();
@@ -142,13 +133,11 @@
 
             <el-row style="margin-top:10px">
               <el-col :span="4">
-                <el-select size="mini" style="width:100%" placeholder="需求项目" v-model="parmValue.demandProject" @change="
-                pageInfo.curr = 1;
-                parmValue.page = 1;
-                searchList();
-               ">
-                  <el-option />
-                </el-select>
+                <search-activity-type style="width:100%" size="mini" :value.sync="parmValue.demandProject" placeholder="需求项目" @change="
+                   pageInfo.curr = 1;
+                   parmValue.page = 1;
+                   searchList();
+                  " />
               </el-col>
 
               <el-col :span="4" style="margin-left:10px">
@@ -167,7 +156,7 @@
                ">
                   <el-option />
                 </el-select> -->
-                <search-customer size="mini" placeholder="需求公司" :value.sync="parmValue.demandEnterprises" @change="
+                <search-customer style="width:100%" size="mini" placeholder="需求公司" :value.sync="parmValue.demandEnterprises" @change="
                   pageInfo.curr = 1;
                   parmValue.page = 1;
                   searchList();

+ 0 - 255
src/views/customerService/demandOrder/letterEditing.vue

@@ -1,255 +0,0 @@
-<template>
-  <div style="padding:10px">
-    <ul style="width:100%;margin-bottom:10px;display:flex;justify-content:flex-end;margin-top:10px;align-items:center;">
-      <li style="line-height:30px;margin-right:20px">
-       <span>非税总报价 : </span>
-       <span>28000</span>
-      </li>
-
-      <li style="line-height:30px;margin-right:20px">
-       <span>含税总报价 : </span>
-       <span>28000</span>
-      </li>
-
-      <li style="line-height:30px;margin-right:20px">
-       <span>总税额 : </span>
-       <span>28000</span>
-      </li>
-
-
-      <li style="margin-right: 10px">
-        <el-button size="mini" type="primary" @click="downloadTemplate">下载模板</el-button>
-      </li>
-
-      <li>
-        <el-button size="mini" type="primary" @click="onSubmit">保存</el-button>
-      </li>
-    </ul>
-
-    <!-- <div v-if="tableData && tableData.length > 0" class="tr" style="padding: 10px 0 0 0">
-    <el-button :size="'mini'" @click="() => tableData = []">取消</el-button>
-    <el-button type="primary" :size="'mini'" @click="onSubmit">提交</el-button>
-    </div> -->
-    <upload-excel :on-success="onSuccess" :before-upload="beforeUpload" />
-
-    <ex-table
-      :columns="[
-        ...columns,{ _slot_:'action', label:' 操作', width:'160px' }
-      ]"
-      :table="table"
-      :data="tableData"
-      style="margin: 15px 0 0 0"
-    >
-      <template #action={scope}>
-        <el-button size="mini" type="text">复制</el-button>
-        <el-button size="mini" type="text">编辑</el-button>
-        <el-button size="mini" type="text" @click="deleteItem(scope.$index)">删除</el-button>
-        <el-button size="mini" type="text">保存</el-button>
-      </template>
-    </ex-table>
-  </div>
-</template>
-
-<script>
-import asyncRequest from "@/apis/service/customerService/demandOrder";
-import companyHelper from '@/mixins/companyHelper'
-import { MessageBox } from 'element-ui'
-import { template } from "./_template"
-import { utils, writeFile } from "xlsx"
-import dayjs from 'dayjs'
-
-import {
-  helper,
-  columns,
-  getTableProperty,
-  createErrorMessage,
-  createFieldVerification,
-  requiredFields,
-} from './_template'
-
-export default {
-  mixins: [companyHelper],
-  props: ['visible'],
-  data() {
-    return {
-      columns,
-      loading: false,
-      tableData: [],
-      table: {
-        stripe: true,
-        border: true,
-        'max-height': '800px'
-      }
-    }
-  },
-  computed: {
-    total:{
-      handler(newVal){
-        newVal.reduce(item => ({
-
-        }),{
-          total:0,
-          includeTaxTotal: 0,
-          notTaxTotal: 0
-        })
-      },
-      deep: true,
-      immediate: true
-    },
-    innerVisible: {
-      get() {
-        return this.visible
-      },
-      set(newVal) {
-        this.$emit('update:visible', newVal)
-      }
-    }
-  },
-  mounted(){
-    this.searchPlanList()
-  },
-  methods: {
-    async searchPlanList(){
-      this.loading = true
-      const { code, data } = await asyncRequest.planList({
-        req_id: this.$route.query.id,
-        size:1000
-      });
-      this.loading = false
-
-      if (code === 1) {
-        const { list, count } = data;
-        this.tableData = list
-        // this.pageInfo.total = count
-      }  else {
-        this.list = [];
-        // this.pageInfo.total = 0;
-      }
-    },
-    deleteItem(index){
-      this.tableData.splice(index, 1)
-    },
-    downloadTemplate(){
-      const workBook = utils.book_new()
-      const workSheet = utils.json_to_sheet(template)
-      utils.book_append_sheet(workBook,workSheet,"sheet")
-
-      writeFile(workBook,"预算函模板.xlsx",{
-        bookType:'xlsx'
-      })
-    },
-    validateTableHeader(header, importHeader) {
-      let isHeaderOk = true
-      if (header.length !== importHeader.length) return false
-      for (const index in header) {
-        const field = header[index]
-        const importField = importHeader[index]
-        if (field !== importField) {
-          console.log(field, importField)
-          isHeaderOk = false
-          break
-        }
-      }
-
-      return isHeaderOk
-    },
-    validateRequiredField(requiredFields) {
-      const verification = createFieldVerification('发票申请编号、发票类型、发票号码、开票日期、税后金额不能为空')
-      const fields = helper.fields(requiredFields)
-      requiredFields[fields[0]].forEach((_, index) => {
-        if (!helper.values(requiredFields, fields, index).every(value => value && String(value).trim() !== '')) {
-          verification.isValid = false
-          verification.notValidRows.push(index + 1)
-        }
-      })
-      return verification
-    },
-    /* 处理不合法的值,提示错误信息,并返回最终的验证状态 **/
-    handleNotValidFields(...validStates) {
-      const messages = {}
-      let isFinalValid = true
-
-      for (const validState of validStates) {
-        const { message, isValid, notValidRows } = validState
-        if (isValid) continue
-        isFinalValid = false
-
-        notValidRows.forEach(row => {
-          if (!messages[row]) messages[row] = []
-          messages[row].push(message)
-        })
-      }
-
-      return {
-        isFinalValid,
-        message: () => !isFinalValid && MessageBox({
-          type: 'warning',
-          title: '数据填写错误',
-          dangerouslyUseHTMLString: true,
-          message: createErrorMessage(messages),
-          customClass: 'error-message__wrapper'
-        })
-      }
-    },
-    /* 校验导入的数据 **/
-    validateFields(tableData = []) {
-      const mapTableFieldToTableData = {}
-      for (const tableItem of tableData) {
-        const propertys = Object.keys(tableItem)
-        for (const property of propertys) {
-          const value = tableItem[property]
-          if (!mapTableFieldToTableData[property]) mapTableFieldToTableData[property] = []
-          mapTableFieldToTableData[property].push(value)
-        }
-      }
-
-      return this.handleNotValidFields(
-        this.validateRequiredField(helper.write(mapTableFieldToTableData, requiredFields))
-      )
-    },
-    mapTemplateItemToTableItem(templateItem) {
-      const tableItem = {}
-      const templatePropertys = Object.keys(templateItem)
-      templatePropertys.forEach(templateProperty => {
-        const tableproperty = getTableProperty(templateProperty)
-        tableItem[tableproperty] = templateItem[templateProperty]
-      })
-      return tableItem
-    },
-    onSuccess({ results: templateItems, header: templateHeader }) {
-      const isHeaderValid = this.validateTableHeader(
-        this.columns.map(({ label }) => label).slice(1),
-        templateHeader
-      )
-      if (!isHeaderValid) {
-        this.$message.warning('表格与导入的表头不一致!')
-        return
-      }
-      if (templateItems.length === 0) {
-        this.$message.warning('导入的表格没有数据!')
-        return
-      }
-      templateItems.forEach(templateItem => {
-        const tableItem = this.mapTemplateItemToTableItem(templateItem)
-        this.tableData.push(tableItem)
-      })
-      this.validateFields(this.tableData).message()
-    },
-    async onSubmit() {
-      this.loading = true
-      const param = {
-        plan_info:[],
-        plan_id:7,
-      }
-      this.loading = false
-      const { code } = await asyncRequest.planUpdate(param)
-    }
-  }
-}
-</script>
-
-<style lang="scss">
-.error-message__wrapper{
-  width: 1024px;
-}
-</style>

+ 24 - 14
src/views/customerService/workbench/detail.vue

@@ -14,7 +14,7 @@
                 <li>任务剩余时间:</li>
                 <li>{{ countdown }}</li>
                 <li>需求公司:</li>
-                <li>{{ sitem.companyNama || '--' }}</li>
+                <li>{{ sitem.companyName || '--' }}</li>
                 <li>需求创建人:</li>
                 <li>{{ sitem.req_user_name || '--' }}</li>
                 <li>联系方式:</li>
@@ -42,26 +42,31 @@
         </div>
 
         <div class="p-right">
-          <div style="display:flex;align-items:center;margin:10px 0px">
+          <!-- <div style="display:flex;align-items:center;margin:10px 0px">
             <p style="margin-right:10px">店铺:</p>
             <search-store size="mini" :value.sync="storeId" />
-          </div>
+          </div> -->
          
-          <el-collapse v-model="actives" v-if="storeId">
+         <!-- v-if="storeId" -->
+          <el-collapse v-model="actives">
             <el-collapse-item title="评估预算函" name="1">
               <letter
+                ref="evaLetter"
                 :status="1"
                 type="budget"
                 :id="sitem.id"
                 :isSelection="true"
                 :readonly="Number(sitem.status) !== 1"
                 @selection="handleSelection($event, 'evalute')"
+                @updateLetter="linkToLetterUpdate"
                 :requsetMethod="requestBudgetLetter"
+                @refresh="refresh('eva')"
               />
             </el-collapse-item>
             <el-collapse-item title="活动方案管理" name="2">
               <letter 
                 :status="2"
+                ref="actLetter"
                 type="activity"
                 :id="sitem.id"
                 :isFile="true"
@@ -69,12 +74,13 @@
                 :readonly="Number(sitem.status) !== 2"
                 :beforeModalVisible="beforeActivityModalVisible"
                 @selection="handleSelection($event, 'activity')"
-                @updateLetter="linkToLetterUpdate('evalute')"
                 :requsetMethod="reqsetActivityLetter"
+                @refresh="refresh('act')"
               />
             </el-collapse-item>
             <el-collapse-item title="计划预算函管理" name="3">
-              <letter 
+              <letter
+                ref="proLetter"
                 :status="3"
                 type="project"
                 :id="sitem.id"
@@ -82,16 +88,16 @@
                 :readonly="Number(sitem.status) !== 3"
                 :beforeModalVisible="beforeProjectModalVisible"
                 @selection="handleSelection($event, 'project')"
-                @updateLetter="linkToLetterUpdate('activity')"
                 :requsetMethod="requsetProjectLetter"
+                @refresh="refresh('pro')"
               />
             </el-collapse-item>
           </el-collapse>
 
-          <div class="empty-warning" v-else>
+          <!-- <div class="empty-warning" v-else>
             <i class="el-icon-warning" style="margin-right:10px" />
             请选择店铺
-          </div>
+          </div> -->
         </div>
       </div>
     </div>
@@ -287,6 +293,13 @@ export default {
 
       return true
     },
+    async refresh(refPrefix){
+      const currentRef = refPrefix + 'Letter'
+      const letters = ['evaLetter','actLetter','proLetter']
+      letters.forEach(letter => {
+        if(letter !== currentRef) this.$refs[letter].searchList()
+      })
+    },
     async requsetProjectLetter(planinfo, file_url){
       const params = {
         status: 3,
@@ -307,18 +320,15 @@ export default {
 
       return asyncRequest.planStatus(params)
     },
-    async requestBudgetLetter(plan_info){
+    async requestBudgetLetter(plan_info,_,store_id){
       const params = {
-        store_id: this.storeId,
         req_id:this.sitem.id,
+        store_id,
         plan_info
       }
 
       return asyncRequest.planCreate(params)
     },
-    linkToLetterUpdate(property){
-      this.$router.push('/customerService/letterEditing?id=' + this.selected[property][0])
-    }
   },
 };
 </script>

+ 33 - 28
src/views/customerService/workbench/index.vue

@@ -2,7 +2,8 @@
   <div class="workbench">
     <div class="workbench-main" v-loading="loading">
         <div class="workbench-main__search">
-          <el-row>
+          <div style="width: 100%">
+            <el-row>
               <el-col :span="4" style="width: 351px;">
                 <period-date-picker
                   :start="parmValue.addtime_start"
@@ -14,17 +15,14 @@
                 />
               </el-col>
 
-              <el-col :span="4" style="width:200px">
-                <el-select v-model="parmValue.city" size="mini" placeholder="活动城市" @change="
-                pageInfo.curr = 1;
-                parmValue.page = 1;
-                searchList();
-               ">
-                  <el-option />
-                </el-select>
+              <el-col :span="4">
+                <search-people-number size="mini" style="width:100%" :data.sync="parmValue.activityPerson" placeholder="活动人数"  @change="
+                  pageInfo.curr = 1;
+                  parmValue.page = 1;
+                  searchList();
+                " />
               </el-col>
                             
-
               <el-col :span="3" style="width: 66px; float: right">
                 <el-button
                   :size="searchSize"
@@ -65,18 +63,20 @@
                 parmValue.page = 1;
                 searchList();
                ">
-                  <el-option />
+                  <el-option v-for="status in demandStatusOptions" 
+                    :key="status.value" 
+                    :value="status.value" 
+                    :label="status.label"
+                   />
                 </el-select>
               </el-col>
 
               <el-col :span="4">
-                <el-select  v-model="parmValue.activityDemand" style="width:100%" size="mini" placeholder="活动需求" @change="
-                pageInfo.curr = 1;
-                parmValue.page = 1;
-                searchList();
-               ">
-                  <el-option />
-                </el-select>
+                <search-demand style="width:100%" size="mini" :value.sync="parmValue.activityDemand"  @change="
+                  pageInfo.curr = 1;
+                  parmValue.page = 1;
+                  searchList();
+                " />
               </el-col>
             </el-row>
 
@@ -109,16 +109,13 @@
               </el-col>
             </el-row>
 
-
             <el-row style="margin-top:10px">
               <el-col :span="4">
-                <el-select size="mini" style="width:100%" placeholder="需求项目" v-model="parmValue.demandProject" @change="
-                pageInfo.curr = 1;
-                parmValue.page = 1;
-                searchList();
-               ">
-                  <el-option />
-                </el-select>
+                <search-activity-type style="width:100%" size="mini" :value.sync="parmValue.demandProject" placeholder="需求项目" @change="
+                   pageInfo.curr = 1;
+                   parmValue.page = 1;
+                   searchList();
+                  " />
               </el-col>
 
               <el-col :span="4" style="margin-left:10px">
@@ -130,15 +127,23 @@
               </el-col>
 
               <el-col :span="4" style="margin-left:10px">
-                <el-select size="mini" placeholder="需求企业" v-model="parmValue.demandEnterprise" @change="
+                <!-- <el-select size="mini" placeholder="需求企业" v-model="parmValue.demandEnterprise" @change="
                 pageInfo.curr = 1;
                 parmValue.page = 1;
                 searchList();
                ">
                   <el-option />
-                </el-select>
+                </el-select> -->
+                <search-customer style="width:100%" size="mini" placeholder="需求公司" :value.sync="parmValue.demandEnterprises" @change="
+                  pageInfo.curr = 1;
+                  parmValue.page = 1;
+                  searchList();
+                  " 
+                />
               </el-col>
             </el-row>
+
+          </div>
         </div>
 
       <ul class="clear po-ul">

+ 61 - 159
src/views/customerService/workbench/letterEditing.vue

@@ -1,78 +1,65 @@
 <template>
-  <div style="padding:10px">
+  <div style="padding:10px" v-loading="loading">
     <ul style="width:100%;margin-bottom:10px;display:flex;justify-content:flex-end;margin-top:10px;align-items:center;">
       <li style="line-height:30px;margin-right:20px">
        <span>非税总报价 : </span>
-       <span>{{tableData.assess_price}}</span>
+       <span>{{Number(total.notTaxTotal).toFixed(2)}}</span>
       </li>
 
       <li style="line-height:30px;margin-right:20px">
        <span>含税总报价 : </span>
-       <span>{{tableData.assess_total_price}}</span>
+       <span>{{Number(total.includeTaxTotal).toFixed(2)}}</span>
       </li>
 
       <li style="line-height:30px;margin-right:20px">
        <span>总税额 : </span>
-       <span>{{tableData.assess_price}}</span>
+       <span>{{Number(total.total).toFixed(2)}}</span>
       </li>
 
-
-      <!-- <li style="margin-right: 10px">
-        <el-button size="mini" type="primary" @click="downloadTemplate">下载模板</el-button>
-      </li> -->
-
       <li>
         <el-button size="mini" type="primary" @click="onSubmit">保存</el-button>
       </li>
     </ul>
 
-    <!-- <div v-if="tableData && tableData.length > 0" class="tr" style="padding: 10px 0 0 0">
-    <el-button :size="'mini'" @click="() => tableData = []">取消</el-button>
-    <el-button type="primary" :size="'mini'" @click="onSubmit">提交</el-button>
-    </div> -->
-    <!-- <upload-excel :on-success="onSuccess" :before-upload="beforeUpload" /> -->
-
     <ex-table
       :columns="[ ...columns,{ _slot_: 'action', label: '操作', width: '160px' } ]"
       :table="table"
       :data="tableData.assessinfo"
       style="margin: 15px 0 0 0"
+      :noPagination="true"
     >
       <template #action={scope}>
         <el-button size="mini" type="text" @click="copyItem(scope.row)">复制</el-button>
-        <el-button size="mini" type="text">编辑</el-button>
-        <el-button size="mini" type="text" @click="deleteItem(scope.row)">删除</el-button>
-        <!-- <el-button size="mini" type="text">保存</el-button> -->
+        <el-button size="mini" type="text" @click="updateItem(scope.$index)">编辑</el-button>
+        <el-button size="mini" type="text" @click="deleteItem(scope.$index)">删除</el-button>
       </template>
     </ex-table>
+
+    <update-modal :sitem="sitem" :visible.sync="visible" @save="handleSave" />
   </div>
 </template>
 
 <script>
 import asyncRequest from "@/apis/service/customerService/workbench";
 import companyHelper from '@/mixins/companyHelper'
-import { MessageBox } from 'element-ui'
-import { template } from "./_template"
-import { utils, writeFile } from "xlsx"
-// import dayjs from 'dayjs'
+import UpdateModal from "./modal.vue"
 
 import {
-  helper,
   columns,
-  getTableProperty,
-  createErrorMessage,
-  createFieldVerification,
-  requiredFields,
 } from './_template'
 
 export default {
   mixins: [companyHelper],
   props: ['visible'],
+  components:{ UpdateModal },
   data() {
     return {
       columns,
+      visible: false,
       loading: false,
       tableData: [],
+      sitem: {},
+      index: -1,
       table: {
         stripe: true,
         border: true,
@@ -81,18 +68,19 @@ export default {
     }
   },
   computed: {
-    total:{
-      handler(newVal){
-        newVal.reduce(item => ({
-
+    total(){
+      console.log(this.tableData.assessinfo)
+      const list = this.tableData.assessinfo || []
+
+      return list.reduce((prev,current) => ({
+          notTaxTotal:Number(prev.notTaxTotal) + Number( current.pay_fee),
+          includeTaxTotal:Number(prev.includeTaxTotal) + Number(current.total_fee),
+          total:Number(prev.total) + Number( current.tax_fee),
         }),{
           total:0,
           includeTaxTotal: 0,
           notTaxTotal: 0
         })
-      },
-      deep: true,
-      immediate: true
     },
     innerVisible: {
       get() {
@@ -107,6 +95,30 @@ export default {
     this.onSearch()
   },
   methods: {
+    async deleteItem(index){
+      const item = this.tableData.assessinfo[index]
+
+      this.$confirm(`是否确认删除预算函 ${item.name}?`, {
+        type:'warning'
+      }).then(async () => {
+        if(!item.id) {
+          this.tableData.assessinfo.splice(index, 1)
+          return
+        }
+
+        this.loading = true
+        const { code } = await asyncRequest.planDelete({ id: item.id })
+        this.loading = false
+        if(code !== 1) return
+
+        this.tableData.assessinfo.splice(index, 1)
+      })
+    },
+    updateItem(index){
+      this.sitem = this.tableData.assessinfo[index]
+      this.index = index
+      this.visible = true
+    },
     async onSearch(){
       this.loading = true
       
@@ -120,138 +132,28 @@ export default {
       this.tableData = data
     },
     async copyItem(row){
-      this.loading = true
-      const { code } = await asyncRequest.planCreate({
-        req_id: this.tableData.req_id,
-        plan_info: [ row ],
-        store_id: 3
-      })
-      this.loading = false
-
-      if(code !== 1) return
-      this.onSearch()
-    },
-    async deleteItem(row){
-      this.loading = true
-      const { code } = await asyncRequest.planDelete({id: row.id})
-      this.loading = false
-      if(code !== 1) return
-      this.onSearch()
-    },
-    downloadTemplate(){
-      const workBook = utils.book_new()
-      const workSheet = utils.json_to_sheet(template)
-      utils.book_append_sheet(workBook,workSheet,"sheet")
-
-      writeFile(workBook,"预算函模板.xlsx",{
-        bookType:'xlsx'
-      })
-    },
-    validateTableHeader(header, importHeader) {
-      let isHeaderOk = true
-      if (header.length !== importHeader.length) return false
-      for (const index in header) {
-        const field = header[index]
-        const importField = importHeader[index]
-        if (field !== importField) {
-          console.log(field, importField)
-          isHeaderOk = false
-          break
-        }
-      }
-
-      return isHeaderOk
-    },
-    validateRequiredField(requiredFields) {
-      const verification = createFieldVerification('发票申请编号、发票类型、发票号码、开票日期、税后金额不能为空')
-      const fields = helper.fields(requiredFields)
-      requiredFields[fields[0]].forEach((_, index) => {
-        if (!helper.values(requiredFields, fields, index).every(value => value && String(value).trim() !== '')) {
-          verification.isValid = false
-          verification.notValidRows.push(index + 1)
-        }
-      })
-      return verification
-    },
-    /* 处理不合法的值,提示错误信息,并返回最终的验证状态 **/
-    handleNotValidFields(...validStates) {
-      const messages = {}
-      let isFinalValid = true
-
-      for (const validState of validStates) {
-        const { message, isValid, notValidRows } = validState
-        if (isValid) continue
-        isFinalValid = false
-
-        notValidRows.forEach(row => {
-          if (!messages[row]) messages[row] = []
-          messages[row].push(message)
-        })
-      }
-
-      return {
-        isFinalValid,
-        message: () => !isFinalValid && MessageBox({
-          type: 'warning',
-          title: '数据填写错误',
-          dangerouslyUseHTMLString: true,
-          message: createErrorMessage(messages),
-          customClass: 'error-message__wrapper'
-        })
-      }
-    },
-    /* 校验导入的数据 **/
-    validateFields(tableData = []) {
-      const mapTableFieldToTableData = {}
-      for (const tableItem of tableData) {
-        const propertys = Object.keys(tableItem)
-        for (const property of propertys) {
-          const value = tableItem[property]
-          if (!mapTableFieldToTableData[property]) mapTableFieldToTableData[property] = []
-          mapTableFieldToTableData[property].push(value)
-        }
-      }
-
-      return this.handleNotValidFields(
-        this.validateRequiredField(helper.write(mapTableFieldToTableData, requiredFields))
-      )
-    },
-    mapTemplateItemToTableItem(templateItem) {
-      const tableItem = {}
-      const templatePropertys = Object.keys(templateItem)
-      templatePropertys.forEach(templateProperty => {
-        const tableproperty = getTableProperty(templateProperty)
-        tableItem[tableproperty] = templateItem[templateProperty]
-      })
-      return tableItem
-    },
-    onSuccess({ results: templateItems, header: templateHeader }) {
-      const isHeaderValid = this.validateTableHeader(
-        this.columns.map(({ label }) => label).slice(1),
-        templateHeader
-      )
-      if (!isHeaderValid) {
-        this.$message.warning('表格与导入的表头不一致!')
-        return
-      }
-      if (templateItems.length === 0) {
-        this.$message.warning('导入的表格没有数据!')
-        return
-      }
-      templateItems.forEach(templateItem => {
-        const tableItem = this.mapTemplateItemToTableItem(templateItem)
-        this.tableData.push(tableItem)
-      })
-      this.validateFields(this.tableData).message()
+      const item = JSON.parse(JSON.stringify(row))
+      delete item.id
+      this.tableData.assessinfo.push(item)
     },
     async onSubmit() {
       this.loading = true
       const param = {
-        plan_info:[],
-        plan_id:7,
+        plan_info:this.tableData.assessinfo.map(({
+          name,  service_cat, price,unit,  num, tax,  id
+        }) => ({
+          name, service_cat, price, unit, num, tax, id
+        })),
+        plan_id:this.$route.query.id,
+        store_id:this.tableData.store_id
       }
       this.loading = false
       const { code } = await asyncRequest.planUpdate(param)
+      if(code !== 1) return
+      this.$router.back()
+    },
+    handleSave(data){
+      this.$set(this.tableData.assessinfo, this.index, data)
     }
   }
 }

+ 155 - 0
src/views/customerService/workbench/modal.vue

@@ -0,0 +1,155 @@
+<template>
+  <el-dialog :visible="innerVisible" title="编辑预算函" center :close-on-click-modal="false" @close="handleClose">
+    <el-form ref="ruleForm" label-width="110px" size="mini" :rules="rules" :model="ruleForm">
+      <el-form-item label="服务名称" prop="name">
+        <el-input placeholder="服务名称" v-model="ruleForm.name" />
+      </el-form-item>
+      <el-form-item label="服务分类" prop="service_cat">
+        <el-input placeholder="服务分类" v-model="ruleForm.service_cat" />
+      </el-form-item>
+
+      <el-form-item label="单价" prop="price">
+        <digital-input
+          :values="ruleForm.price"
+          :placeholder="'单价'"
+          :min="0"
+          :max="100000000000"
+          :position="'right'"
+          :precision="2"
+          :size="'mini'"
+          :controls="false"
+          :append="'元'"
+          @reschange="number_change($event, 'price')"
+        />
+      </el-form-item>
+      
+      <el-form-item label="单位" prop="unit">
+        <el-input v-model="ruleForm.unit" placeholder="单位" />
+      </el-form-item>
+
+      <el-form-item label="数量" prop="num">
+        <digital-input
+          :values="ruleForm.num"
+          :placeholder="'数量'"
+          :min="0"
+          :max="100000000000"
+          :position="'right'"
+          :precision="0"
+          :size="'mini'"
+          :controls="false"
+          :append="''"
+          @reschange="number_change($event, 'num')"
+        />
+      </el-form-item>
+
+       <el-form-item label="税率" prop="tax">
+        <digital-input
+          :values="ruleForm.tax"
+          :placeholder="'数量'"
+          :min="0"
+          :max="100000000000"
+          :position="'right'"
+          :precision="0"
+          :size="'mini'"
+          :controls="false"
+          :append="'%'"
+          @reschange="number_change($event, 'tax')"
+        />
+      </el-form-item>
+
+      <el-form-item class="flex-end">
+        <el-button type="primary" size="mini" @click="onSave">保存</el-button>
+      </el-form-item>
+    </el-form>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  props:['visible','sitem', 'type'],
+  computed:{
+    innerVisible:{
+      get(){
+        return this.visible
+      },
+      set(newVal){
+        this.$emit('update:visible',newVal)
+      }
+    }
+  },
+  watch:{
+    visible(){
+      if(!this.visible) return
+      this.$nextTick(() => this.initForm())
+    }
+  },
+  data(){
+    return {
+      ruleForm:{},
+      rules:{
+        name:[
+          {
+            required:true,
+            message:'请输入服务名称',
+            trigger:'change'
+          }
+        ],
+        service_cat:[
+          {
+            required:true,
+            message:'请输入服务分类ID',
+            trigger:'change'
+          }
+        ],
+        price:[
+          {
+            required:true,
+            message:'请输入单价',
+            trigger:'change'
+          }
+        ],
+        unit:[
+          {
+            required:true,
+            message:'请输入单位ID',
+            trigger:'change'
+          }
+        ],
+        num:[
+          {
+            required:true,
+            message:'请输入数量',
+            trigger:'change'
+          }
+        ],
+       tax:[
+          {
+            required:true,
+            message:'请输入税率',
+            trigger:'change'
+          }
+        ]
+      }
+    }
+  },
+  methods:{
+    initForm(){
+      this.ruleForm = {...this.sitem}
+    },
+    number_change(num,prop){
+      console.log(num)
+      this.ruleForm[prop] = num
+    },
+    handleClose(){
+      this.innerVisible = false
+    },
+    onSave(){
+      this.$refs.ruleForm.validate(async isValid => {
+        if(!isValid) return
+        this.$emit('save', this.ruleForm)
+        this.innerVisible = false
+      })
+    }
+  }
+}
+</script>