snow 1 year ago
parent
commit
c284af6728
34 changed files with 1392 additions and 438 deletions
  1. 1 0
      public/index.html
  2. 7 0
      src/apis/components/letter.js
  3. 5 0
      src/apis/components/search.js
  4. 6 0
      src/components/flow-chart/style.css
  5. 1 1
      src/components/manage/index.js
  6. 187 0
      src/components/manage/src/letter/_columns.js
  7. 134 0
      src/components/manage/src/letter/_template.js
  8. 111 0
      src/components/manage/src/letter/index.vue
  9. 50 0
      src/components/manage/src/letter/previewModal.vue
  10. 247 0
      src/components/manage/src/letter/xlsxUploadModal.vue
  11. 0 120
      src/components/manage/src/settlementBudgetLetter/_template.js
  12. 0 53
      src/components/manage/src/settlementBudgetLetter/index.vue
  13. 0 187
      src/components/manage/src/settlementBudgetLetter/xlsxUploadModal.vue
  14. 0 0
      src/components/manage/src/settlementBudgetLetter/评估(结算or预算)函管理
  15. 7 0
      src/components/search/index.js
  16. 48 0
      src/components/search/src/store.vue
  17. 6 1
      src/plugins/components.js
  18. 127 0
      src/utils/fileType.js
  19. 1 1
      src/views/customerService/demandOrder/components/settlementLetter/xlsxUploadModal.vue
  20. 1 0
      src/views/customerService/demandOrder/components/waitCustomerConfirm.vue
  21. 123 9
      src/views/customerService/demandOrder/components/waitSupplierConfirm.vue
  22. 3 3
      src/views/customerService/demandOrder/detail.vue
  23. 1 4
      src/views/customerService/invoiceApply/detail.vue
  24. 5 9
      src/views/customerService/invoiceApply/index.vue
  25. 1 1
      src/views/customerService/workbench/components/activityLetter/letterEditing.vue
  26. 2 14
      src/views/customerService/workbench/components/baseForm.vue
  27. 8 3
      src/views/customerService/workbench/components/evaluateBudgetLetter/index.vue
  28. 3 3
      src/views/customerService/workbench/components/evaluateBudgetLetter/letterEditing.vue
  29. 1 1
      src/views/customerService/workbench/components/planBudgetLetter/xlsxUploadModal.vue
  30. 113 19
      src/views/customerService/workbench/detail.vue
  31. 10 6
      src/views/customerService/workbench/index.vue
  32. 16 3
      src/views/operate/shop/components/baseForm.vue
  33. 164 0
      src/views/operate/shop/components/mapModal.vue
  34. 3 0
      src/views/operate/shop/detail.vue

+ 1 - 0
public/index.html

@@ -34,6 +34,7 @@
   <script src="./static/vue-router.min.js" rel="preload" as="script"></script>
   <script src="./static/axios@0.21.0.min.js" rel="preload" as="script"></script>
   <script src="./static/dingtalk.open.2.10.3.js" rel="preload" as="script"></script>
+  <script src="//api.map.baidu.com/api?v=2.0&ak=KNAs4HdhPV2Nek2CF4NTGXPvwzDZbfSe"></script>
   <script src="./static/crypto.js"></script>
   <meta name="wpk-bid" content="dta_1_1184953963">
   <script>

+ 7 - 0
src/apis/components/letter.js

@@ -0,0 +1,7 @@
+import http from '@/apis/axios'
+const api = 'admin/planOrder/'
+export default {
+  // 列表
+  list: (data, params) => http(api + 'list', data, 'post', params)
+}
+

+ 5 - 0
src/apis/components/search.js

@@ -0,0 +1,5 @@
+import http from "@/apis/axios";
+const api = "admin/";
+export default {
+    store: (data, params) => http("admin/supplierStore/index", data, "post", params),
+};

+ 6 - 0
src/components/flow-chart/style.css

@@ -52,3 +52,9 @@
 .ol-zoom-in,.ol-zoom-out{
   display: none !important;
 }
+
+
+.tangram-suggestion-main{
+  position: fixed;
+  z-index: 9999999;
+}

+ 1 - 1
src/components/manage/index.js

@@ -1,4 +1,4 @@
-import SettlementBudgetLetter from "./src/settlementBudgetLetter/index.vue"
+import SettlementBudgetLetter from "./src/letter/index.vue"
 import ActivityScheme from "./src/activityScheme/index.vue"
 
 export {

+ 187 - 0
src/components/manage/src/letter/_columns.js

@@ -0,0 +1,187 @@
+const mapFields = {
+  letterNo:'planCode', //评估预算函编号
+  status:'status',  // 状态
+  letter:'plan_file', //评估预算函
+  budgetAmount:'plan_total_price', //评估预算金额
+  supplierStoreName:'store_name', //供应商店铺名称
+  supplierCompanyName:'supplierName', //供应商公司名称
+  creator:'nickname', //创建人
+  createTime:'create_time' //创建时间
+}
+
+export const budget = [
+  {
+      type: 'index',
+      label: '序号',
+      width: '70px'
+  },
+  {
+      prop: mapFields.letterNo,
+      label: '评估预算函编号',
+      width: '120px',
+  },
+  {
+      prop: mapFields.status,
+      label: '是否选中',
+      width: '120px',
+      _slot_:'is_check'
+  },
+  {
+      prop: mapFields.letter,
+      label: '评估预算函',
+      width: '156px',
+  },
+  {
+      prop: mapFields.budgetAmount,
+      label: '评估预算金额',
+      width: '180px',
+  },
+  {
+      prop: mapFields.supplierStoreName,
+      label: '供应商店铺名称',
+      width: '156px',
+  },
+  {
+      prop: mapFields.supplierCompanyName,
+      label: '供应商公司名称',
+      width: '156px',
+  },
+  {
+      prop: mapFields.creator,
+      label: '创建人',
+      width: '150px',
+  },
+  {
+      prop: mapFields.createTime,
+      label: '创建时间',
+      minWidth: '150px',
+  },
+]
+
+export const activity = [
+    {
+        type: 'index',
+        label: '序号',
+        width: '70px'
+    },
+    {
+        prop: mapFields.letterNo,
+        label: '评估预算函编号',
+        width: '120px',
+    },
+    {
+        prop: mapFields.status,
+        label: '是否选中',
+        width: '120px',
+        _slot_:'is_check'
+    },
+    {
+        prop: mapFields.letter,
+        label: '评估预算函',
+        width: '156px',
+    },
+    {
+        prop: mapFields.budgetAmount,
+        label: '评估预算金额',
+        width: '180px',
+    },
+    {
+        prop: mapFields.supplierStoreName,
+        label: '供应商店铺名称',
+        width: '156px',
+    },
+    {
+        prop: mapFields.supplierCompanyName,
+        label: '供应商公司名称',
+        width: '156px',
+    },
+    {
+        prop: mapFields.creator,
+        label: '创建人',
+        width: '150px',
+    },
+    {
+        prop: mapFields.createTime,
+        label: '创建时间',
+        minWidth: '150px',
+    },
+]
+
+export const project = [
+    {
+        type: 'index',
+        label: '序号',
+        width: '70px'
+    },
+    {
+        prop: mapFields.letterNo,
+        label: '评估预算函编号',
+        width: '120px',
+    },
+    {
+        prop: mapFields.status,
+        label: '是否选中',
+        width: '120px',
+        _slot_:'is_check'
+    },
+    {
+        prop: mapFields.letter,
+        label: '评估预算函',
+        width: '156px',
+    },
+    {
+        prop: mapFields.budgetAmount,
+        label: '评估预算金额',
+        width: '180px',
+    },
+    {
+        prop: mapFields.supplierStoreName,
+        label: '供应商店铺名称',
+        width: '156px',
+    },
+    {
+        prop: mapFields.supplierCompanyName,
+        label: '供应商公司名称',
+        width: '156px',
+    },
+    {
+        prop: mapFields.creator,
+        label: '创建人',
+        width: '150px',
+    },
+    {
+        prop: mapFields.createTime,
+        label: '创建时间',
+        minWidth: '150px',
+    },
+]
+
+const mapColumns = {
+    budget,
+    activity,
+    project
+}
+
+
+const mapCheck = {
+    budget:{
+      ok:1,
+      no:0
+    },
+    activity:{
+      ok:2,
+      no:1
+    },
+    project:{
+      ok:3,
+      no:2
+    }
+}
+
+
+
+
+export  {
+  mapColumns,
+  mapCheck
+}

+ 134 - 0
src/components/manage/src/letter/_template.js

@@ -0,0 +1,134 @@
+const mapFields = {
+    name:"name",
+    primaryClassification:'primaryClassification', // 一级分类
+    secondaryClassification:'secondaryClassification',  // 二级分类
+    threeLevelClassification:'service_cat', // 三级分类
+    price:'price', // 单价
+    unit:'unit', // 单位
+    nonTaxQuotes:'assess_price', // 非税报价
+    taxRate:'tax', // 税率
+    tax:'assess_tax_price', // 税额
+    taxIncludedQuote:'assess_total_price', //含税报价
+    num:'num'
+  }
+  
+  const mapTemplateToTable = {
+    '服务名称': mapFields.name,
+    '一级服务分类': mapFields.primaryClassification,
+    '二级服务分类': mapFields.secondaryClassification,
+    '三级服务分类': mapFields.threeLevelClassification,
+    '单价': mapFields.price,
+    '单位': mapFields.unit,
+    '数量': mapFields.num,
+    '非税报价': mapFields.nonTaxQuotes,
+    '税率': mapFields.taxRate,
+    '税额': mapFields.tax,
+    '含税报价': mapFields.taxIncludedQuote,
+  }
+  
+  export const columns = [
+    {
+        type: 'index',
+        label: '序号',
+        width: '70px'
+    },
+     {
+       prop: mapFields.name,
+       label: '服务名称',
+       width: '120px',
+       required: true
+     },
+    {
+      prop: mapFields.primaryClassification,
+      label: '一级服务分类',
+      width: '120px',
+      required: false
+    },
+    {
+      prop: mapFields.secondaryClassification,
+      label: '二级服务分类',
+      width: '120px',
+      required: false
+    },
+    {
+      prop: mapFields.threeLevelClassification,
+      label: '三级服务分类',
+      minWidth: '120px',
+      required: true
+    },
+    {
+      prop: mapFields.price,
+      label: '单价',
+      minWidth: '120px',
+      required: true
+    },
+    {
+      prop: mapFields.unit,
+      label: '单位',
+      minWidth: '120px',
+      required: true
+    },
+    {
+      prop:mapFields.num,
+      label:'数量',
+      minWidth:'100px',
+      required:true
+    },
+    {
+      prop: mapFields.nonTaxQuotes,
+      label: '非税报价',
+      width: '126px',
+      required: false
+    },
+    {
+      prop: mapFields.taxRate,
+      label: '税率',
+      minWidth: '126px',
+      required: true
+    },
+    {
+      prop: mapFields.tax,
+      label: '税额',
+      width: '126px',
+      required: false
+    },
+    {
+      prop: mapFields.taxIncludedQuote,
+      label: '含税报价',
+      width: '120px',
+      required: false
+    }
+  ]
+  
+  export const getTableProperty = (key) => mapTemplateToTable[key]
+  export const getColumn = (key) => columns.find(column => key === column.prop) 
+  
+  export const template = Array(1).fill(1).map(() => Object.keys(mapTemplateToTable).reduce((prev, property) => {
+    prev[property] = ''
+    return prev
+  }, {}))
+  
+  
+  export const requiredFields = [
+    mapFields.name,
+    mapFields.threeLevelClassification,
+    mapFields.price,
+    mapFields.unit,
+    mapFields.num,
+    mapFields.taxRate,
+    mapFields.nonTaxQuotes,
+    mapFields.taxIncludedQuote
+  ]
+  
+  export const requsetFields = [
+    mapFields.name,
+    mapFields.threeLevelClassification,
+    mapFields.price,
+    mapFields.unit,
+    mapFields.num,
+    mapFields.taxRate,
+    // mapFields.tax,
+    // mapFields.nonTaxQuotes,
+    // mapFields.taxIncludedQuote
+  ]
+  

+ 111 - 0
src/components/manage/src/letter/index.vue

@@ -0,0 +1,111 @@
+<template>
+  <div>
+    <div style="display:flex;justify-content:flex-end" v-if="!readonly">
+      <el-button size="mini" @click="onDownloadTemplate">下载{{title}}模板</el-button>
+      <el-button size="mini" type="primary" @click="handleUploadModalVisible">上传{{title}}</el-button>
+    </div>
+    <ex-table
+      :columns="[...(isSelection ? [{type:'selection'}] : []), ...mapColumns[type || 'budget'], { label: '操作', _slot_: 'action', width:'80px',fixed:'right'}]"
+      @selection="handleSelection"
+      :table="table"
+      :data="tableData"
+      style="margin: 15px 0 0 0"
+    >
+      <template #is_check="{scope}">
+        <el-tag size="mini" :type="Number(scope.row.is_check) === mapCheck[type || 'budget'].ok ? '' :'info'">
+         {{Number(scope.row.is_check) === mapCheck[type || 'budget'].ok  ?  "已选择" : "未选择"}}
+        </el-tag>
+      </template>
+
+      <template #action="{scope}">
+        <el-button type="text" size="mini" @click="openModal(scope.row)">查看</el-button>
+      </template>
+    </ex-table>
+
+    <excel-upload-modal 
+      :visible.sync="xlsxVisible"
+      :requsetMethod="requsetMethod"
+      @submit="handleSubmit"
+      @refresh="onSearch"
+      :title="title" 
+      :isFile="isFile"
+    />
+
+    <preview-modal 
+      :sitem="sitem"
+      :visible.sync="previewVisible"
+    />
+  </div>
+</template>
+
+
+<script>
+import ExcelUploadModal from "./xlsxUploadModal.vue"
+import PreviewModal from "./previewModal.vue"
+import asyncRequest from "@/apis/components/letter"
+import { writeFile, utils } from "xlsx";
+import { template } from "./_template"
+import { mapColumns, mapCheck } from "./_columns"
+
+export default {
+  name:'Letter',
+  /* type budget预算函 activity活动方案 project计划 **/
+  props:['title', 'requsetMethod', 'status', 'id', 'isSelection', 'readonly','type', 'beforeModalVisible', 'isFile'],
+  components:{ ExcelUploadModal, PreviewModal },
+  data(){
+    return {
+      table: {
+        stripe: true,
+        border: true,
+        'max-height': '800px'
+      },
+      sitem:{},
+      mapCheck,
+      mapColumns,
+      tableData:[],
+      xlsxVisible:false,
+      previewVisible:false
+    }
+  },
+  mounted(){
+    this.onSearch()
+  },
+  methods:{
+    handleSelection({list}){
+      this.$emit('selection', list.map(({id}) => id))
+    },
+    openModal(row){
+      console.log(this.sitem)
+      this.sitem = row
+      this.previewVisible = true
+    },
+    onDownloadTemplate(){
+      const workBook = utils.book_new()
+      const workSheet = utils.json_to_sheet(template)
+      utils.book_append_sheet(workBook,workSheet,"sheet")
+      writeFile(workBook,`${this.title}模板.xlsx`,{
+        bookType:'xlsx'
+      })
+    },
+    handleUploadModalVisible(){
+      if(this.beforeModalVisible && !this.beforeModalVisible()){
+        return
+      }
+
+      this.xlsxVisible = true
+    },
+    async onSearch(){
+      this.loading = true
+      const { code, data } = await asyncRequest.list({
+        status:this.status,
+        req_id: this.id
+      })
+      this.loading = false
+
+      if(code !== 1) return
+
+      this.tableData = data.list
+    }
+  }
+}
+</script>

+ 50 - 0
src/components/manage/src/letter/previewModal.vue

@@ -0,0 +1,50 @@
+<template>
+  <el-dialog :visible="innerVisible" title="查看预算函" center :close-on-click-modal="false" @close="handleClose">
+    <el-form disabled label-width="110px" size="mini">
+      <el-form-item label="评估预算函编号">
+        <el-input v-model="sitem.planCode" />
+      </el-form-item>
+      <el-form-item label="评估预算金额">
+        <el-input v-model="sitem.plan_total_price" />
+      </el-form-item>
+      <el-form-item label="供应商店铺名称">
+        <el-input v-model="sitem.store_name" />
+      </el-form-item>
+      <el-form-item label="供应商名称">
+        <el-input v-model="sitem.supplierName" />
+      </el-form-item>
+      <el-form-item label="创建人">
+        <el-input v-model="sitem.nickname" />
+      </el-form-item>
+       <el-form-item label="创建时间">
+        <el-input v-model="sitem.create_time" />
+      </el-form-item>
+    </el-form>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  props:['visible','sitem'],
+  computed:{
+    innerVisible:{
+      get(){
+        return this.visible
+      },
+      set(newVal){
+        this.$emit('update:visible',newVal)
+      }
+    }
+  },
+  data(){
+    return {
+
+    }
+  },
+  methods:{
+    handleClose(){
+      this.innerVisible = false
+    }
+  }
+}
+</script>

+ 247 - 0
src/components/manage/src/letter/xlsxUploadModal.vue

@@ -0,0 +1,247 @@
+<template>
+  <el-dialog :title="`上传${title}方案`" :visible="innerVisible" width="1024px" @close="handleClose" center>
+
+    <div v-if="file_url && isFile" style="margin-left:20px">
+      <a :href="file_url">点击下载</a>
+      <el-link
+        :underline="false"
+        @click="deleteUrl('3')"
+        type="warning"
+        style="margin: 0 0 0 16px"
+        >删除</el-link
+      >
+    </div>
+
+    <div class="activity-upload" v-if="!file_url && isFile">
+      <div class="btnupload" style="position: relative">
+        <i class="el-icon-plus avatar-uploader-icon"></i>
+        <file-upload-pdf
+          class="Upload"
+          :accept="'.xlsx,.xls,.pdf,.zip,.rar,.7z'"
+          :multiple="false"
+          :uploadcondition="beforeOtherUpload"
+          @UploadErrorEvent="UploadErrorOtherproof_url"
+          @UploadSuccessEvent="UploadSuccessOtherproof_url"
+        />
+      </div>
+      <div class="txt-tips fl">
+        <p>建议大小:小于5MB</p>
+        <p>文件格式:.xlsx,.xls,.pdf,.zip,.rar,.7z</p>
+      </div>
+    </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>
+      <el-button type="primary" :size="'mini'" @click="onSubmit">提交</el-button>
+      </div>
+      <div v-else>
+        <upload-excel :on-success="onSuccess" :before-upload="beforeUpload" />
+      </div>
+
+      <ex-table
+        :columns="columns"
+        :table="table"
+        :data="tableData"
+        style="margin: 15px 0 0 0"
+      />
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import companyHelper from '@/mixins/companyHelper'
+import { template } from "./_template"
+import { utils, writeFile } from "xlsx"
+
+import {
+  columns,
+  getColumn,
+  requsetFields,
+  requiredFields,
+  getTableProperty,
+} from './_template'
+
+export default {
+  mixins: [companyHelper],
+  props: ['visible', 'title', 'requsetMethod','isFile'],
+  data() {
+    return {
+      columns,
+      loading: false,
+      tableData: [],
+      file_url:"",
+      isInit:true,
+      table: {
+        stripe: true,
+        border: true,
+        'max-height': '800px'
+      }
+    }
+  },
+  computed: {
+    innerVisible: {
+      get() {
+        return this.visible
+      },
+      set(newVal) {
+        this.$emit('update:visible', newVal)
+      }
+    }
+  },
+  methods: {
+    handleClose(){
+      this.tableData = []
+      this.loading = false
+      this.file_url = ""
+      this.innerVisible = false
+    },
+    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
+      console.log(header,importHeader)
+      if (header.length !== importHeader.length) return false
+      for (const index in header) {
+        const field = header[index]
+        const importField = importHeader[index]
+        if (field !== importField) {
+          isHeaderOk = false
+          break
+        }
+      }
+
+      return isHeaderOk
+    },
+    beforeOtherUpload(file) {
+      let isJPG = false;
+      if (
+        file.type === "application/vnd.ms-excel" ||
+        file.type ===
+          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
+        file.type === "application/pdf" ||
+        file.type === "application/x-zip-compressed"
+      ) {
+        isJPG = true;
+      }
+      let name = file.name;
+      let list = name.split(".");
+      if (list[list.length - 1] === "rar" || list[list.length - 1] === "7z" || list[list.length - 1] === "zip") {
+        isJPG = true;
+      }
+
+      const isLt2M = file.size / 1024 / 1024 < 5;
+      if (!isJPG) {
+        this.$message.error("文件格式不正确!");
+      }
+      if (!isLt2M) {
+        this.$message.error("文件大小不能超过 5MB!");
+      }
+      return isJPG && isLt2M;
+    },
+        //其他文件上传失败
+    UploadErrorOtherproof_url(res) {
+      if (res !== "break") {
+        this.$message.error("文件上传失败!");
+      }
+    },
+    async UploadSuccessOtherproof_url(data) {
+      console.log(data)
+      const { url } = data;
+      this.file_url = url;
+      this.$message.success("文件成功!");
+    },
+    isValueNotNull(value){
+      if(!value) return
+      const _value = String(value)
+      return _value.trim() !== ""
+    },
+    /* 校验导入的数据 **/
+    validateFields(tableData = []) {
+      for (const index in tableData) {
+        const line = Number(index) + 1
+        const tableItem = tableData[index]
+        const properties = Object.keys(tableItem)
+        for (const property of properties) {
+          if(requiredFields.includes(property) && !this.isValueNotNull(tableItem[property])){
+            this.$message.warning(`第 ${line} 行 ${getColumn(property).label} 不能为空`)
+            return false
+          }
+        }
+      }
+
+      return true
+    },
+    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)
+    },
+    async onSubmit() {
+      if(!this.validateFields(this.tableData)){
+        return
+      }
+
+      if(this.isFile && !this.file_url){
+        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)
+      this.loading = false
+
+      if(code !== 1) return
+      this.$emit('refresh')
+      this.innerVisible = false
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.error-message__wrapper{
+  width: 1024px;
+}
+
+.activity-upload{
+  margin-bottom: 50px;
+  margin-left: 10px;
+}
+</style>

+ 0 - 120
src/components/manage/src/settlementBudgetLetter/_template.js

@@ -1,120 +0,0 @@
-const mapFields = {
-    letterNo:'letterNo', //评估预算函编号
-    status:'status',  // 状态
-    letter:'letter', //评估预算函
-    budgetAmount:'budgetAmount', //评估预算金额
-    supplierStoreName:'supplierStoreName', //供应商店铺名称
-    supplierCompanyName:'supplierCompanyName', //供应商公司名称
-    creator:'creator', //创建人
-    createTime:'createTime' //创建时间
-}
-
-const mapTemplateToTable = {
-    '评估预算函': mapFields.letterNo,
-    '状态': mapFields.status,
-    '评估预算函': mapFields.letter,
-    '评估预算金额': mapFields.budgetAmount,
-    '供应商店铺名称': mapFields.supplierStoreName,
-    '供应商公司名称': mapFields.supplierCompanyName,
-    '创建人': mapFields.creator,
-    '创建时间': mapFields.createTime
-}
-
-export const getTableProperty = (key) => mapTemplateToTable[key]
-
-export const columns = [
-    {
-        type: 'index',
-        label: '序号',
-        width: '70px'
-    },
-    {
-        prop: mapFields.letterNo,
-        label: '评估预算函编号',
-        width: '120px',
-        required: true
-    },
-    {
-        prop: mapFields.status,
-        label: '状态',
-        width: '120px',
-        required: true
-    },
-    {
-        prop: mapFields.letter,
-        label: '评估预算函',
-        width: '156px',
-        required: true
-    },
-    {
-        prop: mapFields.budgetAmount,
-        label: '评估预算金额',
-        width: '180px',
-        required: true
-    },
-    {
-        prop: mapFields.supplierStoreName,
-        label: '供应商店铺名称',
-        width: '156px',
-        required: true
-    },
-    {
-        prop: mapFields.supplierCompanyName,
-        label: '供应商公司名称',
-        width: '156px',
-        required: false
-    },
-    {
-        prop: mapFields.creator,
-        label: '创建人',
-        width: '150px',
-        required: false
-    },
-    {
-        prop: mapFields.createTime,
-        label: '创建时间',
-        minWidth: '150px',
-        required: false
-    },
-]
-
-export function createErrorMessage(messages) {
-    const rows = Object.keys(messages)
-    return rows.reduce((prev, row, index) => {
-        const suffix = index === rows.length - 1 ? '</ul>' : ''
-        const content = prev + ` <li><strong style="font-weight:700">第${row}行</strong>,${messages[row]} </li> `
-        return content + suffix
-    }, '<ul>')
-}
-
-export const createFieldVerification = (message) => ({
-    notValidRows: [],
-    isValid: true,
-    message
-})
-
-export const template = Array(1).fill(1).map(() => Object.keys(mapTemplateToTable).reduce((prev, property) => {
-    prev[property] = ''
-    return prev
-}, {}))
-
-
-export const requiredFields = []
-
-
-export const helper = {
-    fields(sourceObject) {
-        return Object.keys(sourceObject)
-    },
-    values(sourceObject, fields, index = 0) {
-        return fields.map(field => {
-            return sourceObject[field][index]
-        })
-    },
-    write(sourceObject, fields) {
-        return fields.reduce((prev, currentKey) => ({
-            ...prev,
-            [currentKey]: sourceObject[currentKey]
-        }), {})
-    }
-}

+ 0 - 53
src/components/manage/src/settlementBudgetLetter/index.vue

@@ -1,53 +0,0 @@
-<template>
-  <div>
-    <div style="display:flex;justify-content:flex-end">
-      <el-button size="mini" @click="onDownloadTemplate">下载{{title}}模板</el-button>
-      <el-button size="mini" type="primary" @click="xlsxVisible = true">上传{{title}}函</el-button>
-    </div>
-    <ex-table
-      :columns="columns"
-      :table="table"
-      :data="tableData"
-      style="margin: 15px 0 0 0"
-    />
-    <div style="display:flex;justify-content:flex-end;margin:10px 0px">
-      <el-button size="mini" type="primary">保存</el-button>
-    </div>
-
-    <excel-upload-modal :visible.sync="xlsxVisible" :title="title" />
-  </div>
-</template>
-
-
-<script>
-import ExcelUploadModal from "./xlsxUploadModal.vue"
-import { template, columns } from "./_template"
-import { writeFile, utils } from "xlsx";
-export default {
-  name:'SettlementBudgetLetter',
-  props:['title'],
-  components:{ ExcelUploadModal },
-  data(){
-    return {
-      table: {
-        stripe: true,
-        border: true,
-        'max-height': '800px'
-      },
-      columns,
-      tableData:[],
-      xlsxVisible:false
-    }
-  },
-  methods:{
-    onDownloadTemplate(){
-      const workBook = utils.book_new()
-      const workSheet = utils.json_to_sheet(template)
-      utils.book_append_sheet(workBook,workSheet,"sheet")
-      writeFile(workBook,`${this.title}模板.xlsx`,{
-        bookType:'xlsx'
-      })
-    }
-  }
-}
-</script>

+ 0 - 187
src/components/manage/src/settlementBudgetLetter/xlsxUploadModal.vue

@@ -1,187 +0,0 @@
-<template>
-  <el-dialog
-    center
-    width="1024px"
-    :title="`导入${title}函`"
-    :visible="innerVisible"
-    :close-on-click-modal="false"
-    @close="() => innerVisible = false"
-  >
-    <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>
-    <div v-else>
-      <upload-excel :on-success="onSuccess" :before-upload="beforeUpload" />
-    </div>
-
-    <ex-table
-      :columns="columns"
-      :table="table"
-      :data="tableData"
-      style="margin: 15px 0 0 0"
-    />
-
-    <div style="width:100%;display:flex;justify-content:flex-end;margin-top:10px;padding:0px 10px">
-      <el-button size="mini" type="primary">保存</el-button>
-    </div>
-  </el-dialog>
-</template>
-
-<script>
-import companyHelper from '@/mixins/companyHelper'
-import { MessageBox } from 'element-ui'
-import dayjs from 'dayjs'
-
-import {
-  helper,
-  columns,
-  getTableProperty,
-  createErrorMessage,
-  createFieldVerification,
-  requiredFields,
-} from './_template'
-
-export default {
-  mixins: [companyHelper],
-  props: ['visible','title'],
-  data() {
-    return {
-      columns,
-      loading: false,
-      tableData: [],
-      table: {
-        stripe: true,
-        border: true,
-        'max-height': '800px'
-      }
-    }
-  },
-  computed: {
-    innerVisible: {
-      get() {
-        return this.visible
-      },
-      set(newVal) {
-        this.$emit('update:visible', newVal)
-      }
-    }
-  },
-  methods: {
-    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() {
-      const { message, isFinalValid } = this.validateFields(this.tableData)
-      if (!isFinalValid) return message()
-
-      const list = this.tableData.map(tableItem => requsetFields.reduce((prev, currentKey) => ({
-        ...prev,
-        [currentKey]: currentKey === PROPERTYS.SEND_TIME ? dayjs(tableItem[currentKey] * 1000).format('YYYY-MM-DD HH:mm:ss') : tableItem[currentKey]
-      }), {}))
-
-      this.loading = true
-    }
-  }
-}
-</script>
-
-<style lang="scss">
-.error-message__wrapper{
-  width: 1024px;
-}
-</style>

+ 0 - 0
src/components/manage/src/settlementBudgetLetter/评估(结算or预算)函管理


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

@@ -0,0 +1,7 @@
+import SearchStore from "./src/store.vue"
+
+const searchComponents = [
+  SearchStore
+]
+
+export default searchComponents

+ 48 - 0
src/components/search/src/store.vue

@@ -0,0 +1,48 @@
+<template>
+  <el-select
+    v-model="_value"
+    :size="size" 
+    remote
+    :remote-method="onFetch"
+    placeholder="请选择店铺"
+    :loading="loading"
+    reserve-keyword
+    filterable
+  >
+    <el-option v-for="item in list" :key="item.id" :value="item.id" :label="item.store_name" />
+  </el-select>
+</template>
+
+
+<script>
+import asyncRequest from "@/apis/components/search"
+export default {
+  name:'SearchStore',
+  props:['size', 'value'],
+  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.store({store_name: keyword})
+      if(code !== 1) return
+      this.list = data.list
+    }
+  }
+}
+</script>

+ 6 - 1
src/plugins/components.js

@@ -2,6 +2,8 @@ import { CredentialsNode, NormalNode, CreateInviceNode, UploadInvoiceNode} from
 import { SettlementBudgetLetter, ActivityScheme } from "@/components/manage"
 import { TableEditor } from "@/components/tableEditor"
 
+import searchComponents from "@/components/search"
+
 const components = [
   NormalNode,
   CredentialsNode,
@@ -15,7 +17,10 @@ const components = [
 ]
 
 export const setupComponets = function(app){
-  components.forEach(component => {
+  [
+    ...components,
+    ...searchComponents
+  ].forEach(component => {
     app.component(component.name,component)
   })
 }

+ 127 - 0
src/utils/fileType.js

@@ -0,0 +1,127 @@
+/**
+* @param: fileName - 文件名称
+* @param: 数据返回 1) 无后缀匹配 - false
+* @param: 数据返回 2) 匹配图片 - image
+* @param: 数据返回 3) 匹配 txt - txt
+* @param: 数据返回 4) 匹配 excel - excel
+* @param: 数据返回 5) 匹配 word - word
+* @param: 数据返回 6) 匹配 pdf - pdf
+* @param: 数据返回 7) 匹配 ppt - ppt
+* @param: 数据返回 8) 匹配 视频 - video
+* @param: 数据返回 9) 匹配 音频 - radio
+* @param: 数据返回 10) 其他匹配项 - other
+* @author: ljw
+**/
+
+const mapFileType = {
+  'image': "图片类型",
+  'text': "文本类型",
+  'excel': "excel类型",
+  'word': "word类型",
+  'pdf': "pdf类型",
+  'ppf': "ppt类型",
+  'video': "视频类型",
+  'radio': "音频类型"
+}
+
+export const fileSuffixTypeUtil = {
+  matchFileSuffixType (fileName) {
+    // 后缀获取
+    var suffix = ''
+    // 获取类型结果
+    var result = ''
+    try {
+      var flieArr = fileName.split('.')
+      suffix = flieArr[flieArr.length - 1]
+    } catch (err) {
+      suffix = ''
+    }
+    // fileName无后缀返回 false
+    if (!suffix) {
+      result = false
+      return result
+    }
+    // 图片格式
+    var imglist = ['png', 'jpg', 'jpeg', 'bmp', 'gif']
+    // 进行图片匹配
+    result = imglist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'image'
+      return result
+    }
+    // 匹配txt
+    var txtlist = ['txt']
+    result = txtlist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'txt'
+      return result
+    }
+    // 匹配 excel
+    var excelist = ['xls', 'xlsx']
+    result = excelist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'excel'
+      return result
+    }
+    // 匹配 word
+    var wordlist = ['doc', 'docx']
+    result = wordlist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'word'
+      return result
+    }
+    // 匹配 pdf
+    var pdflist = ['pdf']
+    result = pdflist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'pdf'
+      return result
+    }
+    // 匹配 ppt
+    var pptlist = ['ppt']
+    result = pptlist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'ppt'
+      return result
+    }
+    // 匹配 视频
+    var videolist = ['mp4', 'm2v', 'mkv']
+    result = videolist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'video'
+      return result
+    }
+    // 匹配 音频
+    var radiolist = ['mp3', 'wav', 'wmv']
+    result = radiolist.some(function (item) {
+      return item == suffix
+    })
+    if (result) {
+      result = 'radio'
+      return result
+    }
+    // 其他 文件类型
+    result = 'other'
+    return result
+  },
+  getFIieTypeName(type){
+    console.log(type)
+    let typeName = mapFileType[type]
+    typeName = typeName || '其他类型'
+    return typeName
+  }
+}

+ 1 - 1
src/views/customerService/demandOrder/components/settlementLetter/xlsxUploadModal.vue

@@ -231,7 +231,7 @@ export default {
         this.$emit("refresh")
       }
 
-      this.loading = true
+      this.loading = false
     }
   }
 }

+ 1 - 0
src/views/customerService/demandOrder/components/waitCustomerConfirm.vue

@@ -121,6 +121,7 @@ export default {
       }
     },
     beforeVideoUpload(file) {
+      console.log(file.type)
       let isJPG = false;
       if (file.type === "video/mp4" || file.type === "video/avi") {
         isJPG = true;

+ 123 - 9
src/views/customerService/demandOrder/components/waitSupplierConfirm.vue

@@ -1,18 +1,132 @@
 <template>
-  <el-table border size="mini">
-    <el-table-column label="计划编号" />
-    <el-table-column label="类型" />
-    <el-table-column label="预览" />
-    <el-table-column label="创建人" />
-    <el-table-column label="创建时间" />
-    <el-table-column label="操作" />
-  </el-table>
+  <div>
+    <div class="activity-upload" style="padding-bottom:20px">
+      <div class="btnupload">
+         <i class="el-icon-plus avatar-uploader-icon"></i>
+         <file-upload-pdf
+           class="Upload"
+           :accept="'.xlsx,.xls,.pdf,.zip,.rar,.7z'"
+           :multiple="false"
+           :uploadcondition="beforeOtherUpload"
+           @UploadErrorEvent="UploadErrorOtherproof_url"
+           @UploadSuccessEvent="UploadSuccessOtherproof_url"
+         />
+       </div>
+       <div class="txt-tips fl">
+         <p>建议大小:小于5MB</p>
+         <p>文件格式:.xlsx,.xls,.pdf,.zip,.rar,.7z</p>
+      </div>
+    </div>
+
+    <div style="display:flex">
+      <p style="font-size:14px;margin-left:5px;margin-right:10px">现场资料:</p>
+      <el-table border size="mini" :data="proof_url">
+        <!-- <el-table-column label="计划编号" /> -->
+        <el-table-column label="文件名" prop="name" />
+        <el-table-column label="类型">
+          <template slot-scope="scope">
+            {{ getFIieTypeName(matchFileSuffixType(scope.row.name)) }}
+          </template>
+        </el-table-column>
+        <!-- <el-table-column label="预览" /> -->
+        <!-- <el-table-column label="创建人" /> -->
+        <!-- <el-table-column label="创建时间" /> -->
+        <el-table-column label="操作">
+          <template slot-scope="scope">
+            <el-button type="text" size="mini" @click="deleteItem(scope.$index)">删除</el-button>
+            <el-button type="text" size="mini" @click="previewItem(scope.row.url)">预览</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <div style="display:flex;justify-content:flex-end;margin:10px 0px">
+      <el-button size="mini" type="primary" @click="onSubmit" :loading="loading">保 存</el-button>
+    </div>
+  </div>
 </template>
 
 <script>
+import { fileSuffixTypeUtil } from "@/utils/fileType"
+import asyncRequest from "@/apis/service/customerService/demandOrder";
+const { matchFileSuffixType,getFIieTypeName } = fileSuffixTypeUtil
 export default {
+  props: ['sitem'],
   data(){
-    return {}
+    return {
+      loading:false,
+      proof_url:[]
+    }
+  },
+  methods:{
+    matchFileSuffixType,
+    getFIieTypeName,
+    deleteItem(index){
+      this.proof_url.splice(index,1)
+    },
+    previewItem(url){
+      console.log(url)
+      window.open(url)
+    },
+    beforeOtherUpload(file) {
+      let isJPG = false;
+      if (
+        file.type === "application/vnd.ms-excel" ||
+        file.type ===
+          "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
+        file.type === "application/pdf" ||
+        file.type === "application/x-zip-compressed"
+      ) {
+        isJPG = true;
+      }
+      let name = file.name;
+      let list = name.split(".");
+      if (list[list.length - 1] === "rar" || list[list.length - 1] === "7z" || list[list.length - 1] === "zip") {
+        isJPG = true;
+      }
+
+      const isLt2M = file.size / 1024 / 1024 < 5;
+      if (!isJPG) {
+        this.$message.error("文件格式不正确!");
+      }
+      if (!isLt2M) {
+        this.$message.error("文件大小不能超过 5MB!");
+      }
+      return isJPG && isLt2M;
+    },
+        //其他文件上传失败
+    UploadErrorOtherproof_url(res) {
+      if (res !== "break") {
+        this.$message.error("文件上传失败!");
+      }
+    },
+    async UploadSuccessOtherproof_url(data) {
+      const { url, name } = data;
+      this.proof_url.push({ url, name });
+
+      console.log(this.proof_url)
+      this.$message.success("文件成功!");
+    },
+
+    async onSubmit(){
+      if(this.proof_url.length === 0){
+        this.$message.warning('请上传现场资料')
+        return
+      }
+
+      this.loading = true
+      
+      const params = {
+        id: this.sitem.id, 
+        proof_url: this.proof_url.map(({url}) => url),
+        status: 7 
+      }
+
+      const { code } = await asyncRequest.proofCheck(params)
+      this.loading = false
+      if(code !== 1) return
+      this.$emit('refresh')
+    }
   }
 }
 </script>

+ 3 - 3
src/views/customerService/demandOrder/detail.vue

@@ -28,8 +28,8 @@
             </el-collapse-item>
 
             <el-collapse-item title="待供应商确认已执行" name="6" v-if="Number(sitem.status) === 6">
-              <!-- <wait-supplier-confirm /> -->
-              <credentials-node @confirm="handleSupplierConfirm($event)" />
+              <wait-supplier-confirm :sitem="sitem" @refresh="initData"  />
+              <!-- <credentials-node @confirm="handleSupplierConfirm($event)" /> -->
             </el-collapse-item>
 
             <el-collapse-item title="待客户确认已执行" name="7" v-if="Number(sitem.status) === 7">
@@ -37,7 +37,7 @@
             </el-collapse-item>
 
             <el-collapse-item title="待供应商上传结算函" name="8" v-if="Number(sitem.status) === 9">
-              <!-- <settlement-budget-letter title="结算" /> -->
+              <!-- <letter title="结算" /> -->
               <settlement-letter :sitem="sitem"  @refresh="initData" />
             </el-collapse-item>
 

+ 1 - 4
src/views/customerService/invoiceApply/detail.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="bargainListDetail">
-    <div class="bargainListDetail-main" v-if="powers.some((i) => i == '007')">
+    <div class="bargainListDetail-main">
       <el-tabs v-model="projectTabs" v-loading="loading">
         <el-tab-pane label="需求订单详情" name="1">
           <el-collapse v-model="activeNames" style="margin: -18px 0 0 0">
@@ -25,9 +25,6 @@
         </el-tab-pane>
       </el-tabs>
     </div>
-    <div v-else>
-      <no-auth></no-auth>
-    </div>
   </div>
 </template>
 <script>

+ 5 - 9
src/views/customerService/invoiceApply/index.vue

@@ -1,8 +1,6 @@
 <template>
   <div class="bargainList pagePadding">
-    <div
-      v-if=" powers.some((i) => i == '001')"
-    >
+    <div>
       <ex-table
         v-loading="loading"
         :table="table"
@@ -206,9 +204,6 @@
         </template>
       </ex-table>
     </div>
-    <div v-else>
-      <no-auth></no-auth>
-    </div>
   </div>
 </template>
 <script>
@@ -249,7 +244,7 @@ export default {
       customerCode: [], //客户公司code
       statusList,
       sitem: null,
-      loading: true,
+      loading: false,
       showModel: false,
       isDetail: false,
       modelId: 0,
@@ -327,11 +322,11 @@ export default {
         this.parmValue.select = this.select ;
         // this.parmValue.sselect = this.sselect ;
         this.parmValue.s_input= this.s_input;
-        //
-         let routerModel = {
+        let routerModel = {
           options: JSON.parse(JSON.stringify(this.parmValue)),
           router: this.$route.path,
         };
+
         model.preModel = JSON.stringify(routerModel);
         
         this.routeGoto(toRouter, model);
@@ -399,6 +394,7 @@ export default {
     },
     // 列表搜索
     async searchList() {
+      return
       if (
         (this.parmValue.createStart !== "" && this.parmValue.createEnd === "") ||
         (this.parmValue.createStart === "" && this.parmValue.createEnd !== "")

+ 1 - 1
src/views/customerService/workbench/components/activityLetter/letterEditing.vue

@@ -233,7 +233,7 @@ export default {
         this.$emit("refresh")
       }
 
-      this.loading = true
+      this.loading = false
     }
   }
 }

+ 2 - 14
src/views/customerService/workbench/components/baseForm.vue

@@ -180,6 +180,7 @@
               />
             </el-form-item>
           </el-col>
+
           <el-col :span="12" style="padding: 0 0 0 15px">
             <el-table
               :data="spec_tableData"
@@ -222,7 +223,7 @@
                     <i
                       class="el-icon-delete tb-icon"
                       @click="openDelete(scope.$index)"
-                    ></i>
+                    />
                   </el-tooltip>
                 </template>
               </el-table-column>
@@ -634,18 +635,6 @@
             </i>
           </div>
         </el-form-item>
-        <!-- <i class="el-icon-plus avatar-uploader-icon">
-          
-        </i>
-            <file-upload
-              class="Upload"
-              :accept="'.jpg,.png,.jpeg'"
-              :multiple="true"
-              :disabled="false"
-              :uploadcondition="beforeAvatarUpload"
-              @UploadErrorEvent="UploadErrorEventgood_img"
-              @UploadSuccessEvent="UploadSuccessEventgood_img"
-            ></file-upload> -->
       </el-col>
     </el-row>
   </el-form>
@@ -694,7 +683,6 @@ export default {
       }
     },
   },
-
   data() {
     return {
       areaInfo:{

+ 8 - 3
src/views/customerService/workbench/components/evaluateBudgetLetter/index.vue

@@ -23,7 +23,13 @@
       </template>
     </ex-table>
 
-    <letter-modal :visible.sync="xlsxVisible" :sitem="sitem" :title="title" @refresh="refresh" />
+    <letter-modal 
+      :visible.sync="xlsxVisible" 
+      :sitem="sitem" 
+      :title="title" 
+      :storeId="storeId" 
+      @refresh="refresh" 
+    />
   </div>
 </template>
 
@@ -37,7 +43,7 @@ import asyncRequest from "@/apis/service/customerService/workbench";
 
 export default {
   name:'SettlementBudgetLetter',
-  props:["sitem","readonly"],
+  props:["sitem", "readonly", "storeId"],
   components:{ LetterModal },
   data(){
     return {
@@ -81,7 +87,6 @@ export default {
 
       if(code === 1){
         const { list = [], count = 0 } = data
-        console.log(this.planList)
         this.planList = list;
         this.pageInfo.total = count
       }

+ 3 - 3
src/views/customerService/workbench/components/evaluateBudgetLetter/letterEditing.vue

@@ -35,7 +35,7 @@ import {
 
 export default {
   mixins: [companyHelper],
-  props: ['visible', 'sitem'],
+  props: ['visible', 'sitem', 'storeId'],
   data() {
     return {
       columns,
@@ -147,7 +147,7 @@ export default {
       }), {}))
 
       const params = {
-        store_id: 1,
+        store_id: this.storeId,
         req_id:this.sitem.id,
         plan_info
       }
@@ -160,7 +160,7 @@ export default {
         this.$emit("refresh")
       }
 
-      this.loading = true
+      this.loading = false
     }
   }
 }

+ 1 - 1
src/views/customerService/workbench/components/planBudgetLetter/xlsxUploadModal.vue

@@ -233,7 +233,7 @@ export default {
         this.$emit("refresh")
       }
 
-      this.loading = true
+      this.loading = false
     }
   }
 }

+ 113 - 19
src/views/customerService/workbench/detail.vue

@@ -41,35 +41,59 @@
           </div>
         </div>
         <div class="p-right">
-          <el-collapse v-model="actives">
+          <div style="display:flex;align-items:center;margin:10px 0px">
+            <p style="margin-right:10px">店铺:</p>
+            <search-store size="mini" :value.sync="storeId" />
+          </div>
+
+          <el-collapse v-model="actives" v-if="storeId">
             <el-collapse-item title="评估预算函" name="1">
-              <evalute-budget-letter 
-                :sitem="sitem" 
+              <letter 
+                :status="1"
+                type="budget"
+                title="预算函"
+                :id="sitem.id"
+                :isSelection="true"
                 :readonly="Number(sitem.status) !== 1"
-                @selectionChange="handleSelection($event, 'evalute')"
-                @refresh="initForm" 
+                @selection="handleSelection($event, 'evalute')"
+                :requsetMethod="requestBudgetLetter"
               />
             </el-collapse-item>
 
             <el-collapse-item title="活动方案管理" name="2">
-              <activity-letter 
-                :sitem="sitem" 
-                :readonly="Number(sitem.status) !== 2" 
-                :evalute="selected.evalute"
-                @selectionChange="handleSelection($event, 'activity')"
-                 @refresh="initForm"
+              <letter 
+                :status="2"
+                type="activity"
+                title="活动方案"
+                :id="sitem.id"
+                :isFile="true"
+                :isSelection="true"
+                :readonly="Number(sitem.status) !== 2"
+                :beforeModalVisible="beforeActivityModalVisible"
+                @selection="handleSelection($event, 'activity')"
+                :requsetMethod="reqsetActivityLetter"
               />
             </el-collapse-item>
 
             <el-collapse-item title="计划预算函管理" name="3">
-              <plan-budget-letter                 
-                :sitem="sitem" 
-                :readonly="Number(sitem.status) !== 3" 
-                :activity="selected.activity"
-                @refresh="initForm"
-            />
+              <letter 
+                :status="3"
+                type="project"
+                title="计划预算函"
+                :id="sitem.id"
+                :isFile="true"
+                :readonly="Number(sitem.status) !== 3"
+                :beforeModalVisible="beforeProjectModalVisible"
+                @selection="handleSelection($event, 'activity')"
+                :requsetMethod="requsetProjectLetter"
+              />
             </el-collapse-item>
           </el-collapse>
+
+          <div class="empty-warning" v-else>
+            <i class="el-icon-warning" style="margin-right:10px" />
+            请选择店铺
+          </div>
         </div>
       </div>
     </div>
@@ -77,12 +101,12 @@
 </template>
 <script>
 import asyncRequest from "@/apis/service/customerService/workbench";
-import resToken from "@/mixins/resToken";
-import { mapGetters } from "vuex";
 import baseForm from "./components/baseForm";
 import EvaluteBudgetLetter from "./components/evaluateBudgetLetter/index.vue"
 import PlanBudgetLetter from "./components/planBudgetLetter/index.vue"
 import ActivityLetter from "./components/activityLetter/index.vue"
+import resToken from "@/mixins/resToken";
+import { mapGetters } from "vuex";
 import dayjs from "dayjs"
 
 export default {
@@ -107,6 +131,7 @@ export default {
   },
   data() {
     return {
+      storeId: "",
       countdown:'00:00:00',
       timer:null,
       actives:["1","2","3"],
@@ -189,6 +214,8 @@ export default {
       return result;
     },
     async initData() {
+      console.log(asyncRequest)
+
       const { code, message, data } = await asyncRequest.detail({
         id: this.queryId,
       });
@@ -212,6 +239,7 @@ export default {
       }
     },
     handleSelection(val, key){
+      console.log(val)
       this.selected[key] = val
     },
     async repeat_initData() {
@@ -231,6 +259,61 @@ export default {
       this.editId = bidNo;
       this.editType = type;
       this.getNewTime();
+    },
+    beforeActivityModalVisible(){
+      if(this.selected.evalute.length === 0){
+        this.$message.warning('必须选择一个评估预算函')
+        return false
+      }
+
+      if(this.selected.evalute.length > 1){
+        this.$message.warning('只能选择一个评估预算函')
+        return false
+      }
+
+      return true
+    },
+    beforeProjectModalVisible(){
+      if(this.selected.activity.length === 0){
+        this.$message.warning('必须选择一个活动方案')
+        return false
+      }
+
+      if(this.selected.activity.length > 1){
+        this.$message.warning('只能选择一个活动方案')
+        return false
+      }
+
+      return true
+    },
+    async requsetProjectLetter(planinfo, file_url){
+      const params = {
+        status: 3,
+        id: this.selected.activity[0],
+        planinfo,
+        file_url
+      }
+
+      return asyncRequest.planStatus(params)
+    },
+    async reqsetActivityLetter(planinfo, file_activty_url){
+      const params = {
+        status: 2,
+        id: this.selected.evalute[0],
+        planinfo,
+        file_activty_url
+      }
+
+      return asyncRequest.planStatus(params)
+    },
+    async requestBudgetLetter(plan_info){
+      const params = {
+        store_id: this.storeId,
+        req_id:this.sitem.id,
+        plan_info
+      }
+
+      return asyncRequest.planCreate(params)
     }
   },
 };
@@ -346,4 +429,15 @@ export default {
     }
   }
 }
+
+.empty-warning{
+  display: flex;
+  justify-content: center;
+  align-content: center;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  // margin-top: 100px;
+}
 </style>

+ 10 - 6
src/views/customerService/workbench/index.vue

@@ -506,12 +506,17 @@ export default {
         }
       }
 
-      var result = "" + parseInt(secondTime) + ":";
+      const s = String(secondTime)
+      var result = s.length === 1 ? '0' + s : s
+
+
       if(minuteTime > 0) {
-        result = "" + parseInt(minuteTime) + ":" + result;
+        const m = String(minuteTime)
+        result = "" + (m.length === 1 ? '0' + m : m) + ":" + result;
       }
       if(hourTime > 0) {
-        result = "" + parseInt(hourTime) + ":" + result;
+        const h =  String(hourTime)
+        result = "" + (h.length === 1 ? '0' + h : h) + ":" + result;
       }
       return result;
     },
@@ -534,12 +539,11 @@ export default {
         this.loading = true;
         const { code, data } = await asyncRequest.list({
           ...this.parmValue,
-          size:15
+          size: 15
         });
 
         if (code === 1) {
           const { list, count } = data;
-
           
           this.countdownMaps = list.reduce((prev,current) => {
             return {
@@ -553,7 +557,7 @@ export default {
               ...prev,
               [current.id]:setInterval(() => {
                 let now = dayjs(new Date())
-                const minuend = now.diff(current.req_end, 'second')
+                const minuend = now.diff(current.req_endtime, 'second')
                 this.countdownMaps[current.id] = minuend < 0 ? this.getTime(Math.abs(minuend)) : '00:00:00'
               },1000)
             }

+ 16 - 3
src/views/operate/shop/components/baseForm.vue

@@ -152,18 +152,25 @@
     <el-col :span="24"><div class="supplierAdd-title">门店信息</div></el-col>
     <el-col :span="24">
       <el-form-item label="门店地址" prop="storeAddr">
-        <div id="map" />
+        <div style="display:flex">
+          <el-input :value="toponym" />
+          <el-button style="margin-left:10px" type="primary" @click="visible = true">选择地址</el-button>
+        </div>
       </el-form-item>
     </el-col>
     <el-col :span="24" class="flex-end">
       <el-button type="primary" @click="save" size="mini">保存</el-button>
     </el-col>
+
+    <map-modal :visible.sync="visible" :toponym="toponym" @save="handleMapSelection" />
   </el-form>
 </template>
 <script>
 import asyncRequest from "@/apis/service/operate/shop";
 import asyncRequestStoreType from "@/apis/service/serviceParam/storeType";
 import asyncRequestSupplier from "@/apis/service/operate/supplier";
+import MapModal from "./mapModal.vue"
+
 import Map from "ol/Map"; //地图初始化
 import * as source from "ol/source";
 import Feature from "ol/Feature";
@@ -203,6 +210,7 @@ let key = "4c3306473a0aa048196208f774b491a5";
 export default {
   name: "SupplierAdd",
   mixins: [resToken],
+  components:{ MapModal },
   props: ["showModel", "id", "type", "sitem"],
   data() {
     const validatemobile = (rule, value, callback) => {
@@ -243,11 +251,13 @@ export default {
       }
     };
     return {
+      visible:false,
       parmValue: {
         page: 1, // 页码
         size: 99999, // 每页显示条数
         limit: 99999,
       },
+      toponym:"",
       map: null,
       feature: null,
       loading: false,
@@ -289,8 +299,8 @@ export default {
     };
   },
   mounted() {
-    this.initMap();
-    this.registerMapEvent();
+    // this.initMap();
+    // this.registerMapEvent();
     this.initForm();
   },
   methods: {
@@ -390,6 +400,9 @@ export default {
         }
       });
     },
+    handleMapSelection({ name, point }){
+      this.toponym = name
+    },
     resetFormData() {
       this.ruleForm = {
         ...formItem,

+ 164 - 0
src/views/operate/shop/components/mapModal.vue

@@ -0,0 +1,164 @@
+<template>
+  <el-dialog :visible="_visible" title="选择地址" @close="_visible = false">
+	  <div id="r-result">
+      <p>请输入:</p>
+      <input ref="input" size="mini" type="text" id="suggestId" :value="value"/>
+    </div>
+	  <div id="l-map" ref="map" />
+	  <div 
+      id="searchResultPanel" 
+      style="border:1px solid #C0C0C0;width:150px;height:auto; display:none;" 
+    />
+
+    <div class="flex-end" style="margin-top:10px">
+      <el-button type="primary" size="mini" @click="save">保存</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  name:'MapModal',
+  props:['visible', 'toponym'],
+  data(){
+    return {
+      isInit: true,
+      value: "",
+      point: []
+    }
+  },
+  computed:{
+    _visible:{
+      get(){
+        return this.visible
+      },
+      set(newVal){
+        this.$emit('update:visible',newVal)
+      }
+    }
+  },
+  watch:{
+    visible(newVal){
+      if(!newVal) return
+      this.$nextTick(() => {
+        if(this.isInit){
+          this.initMap()
+          this.isInit = false
+          return
+        }
+
+        this.initValue()
+      })  
+    }
+  },
+  methods:{
+    initMap(){
+      this.createMap()
+      this.createAutoComplete()
+      this.registerHightlightEvent()
+      this.registerConfirmEvent()
+      this.registerConfirmEvent()
+    },
+    createMap(){
+      this.map = new BMap.Map('l-map')
+      this.map.centerAndZoom('北京',28)
+    },
+    createAutoComplete(){
+      this.ac = new BMap.Autocomplete({
+        input:'suggestId',
+        localtion: this.map
+      })
+    },
+    registerHightlightEvent(){
+      this.ac.addEventListener('onhighlight',(e) => {
+         var str = "";
+		     var _value = e.fromitem.value;
+		     var value = "";
+		     if (e.fromitem.index > -1) {
+		     	value = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
+		     }    
+		     str = "FromItem<br />index = " + e.fromitem.index + "<br />value = " + value;
+     
+		     value = "";
+		     if (e.toitem.index > -1) {
+		     	_value = e.toitem.value;
+		     	value = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
+		     }    
+		     str += "<br />ToItem<br />index = " + e.toitem.index + "<br />value = " + value;
+		     document.getElementById("searchResultPanel").innerHTML = str;
+      })
+    },
+    registerConfirmEvent(){
+      this.ac.addEventListener("onconfirm", (e) => {   //鼠标点击下拉列表后的事件
+        var _value = e.item.value;
+	    	this.value = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
+	    	document.getElementById("searchResultPanel").innerHTML ="onconfirm<br />index = " + e.item.index + "<br />myValue = " + this.value;
+	    	this.setPlace();
+	    });
+    },
+    setPlace(){
+	    this.map.clearOverlays();    //清除地图上所有覆盖物
+	    
+      const onSearchComplete = () => {
+        const { point} = local.getResults().getPoi(0)
+
+        this.point = [point.lat , point.lng]
+        // const pp = local.getResults().getPoi(0).point;    //获取第一个智能搜索的结果
+        
+	    	this.map.centerAndZoom(point, 18);
+	    	this.map.addOverlay(new BMap.Marker(point));    //添加标注
+	    }
+
+	    var local = new BMap.LocalSearch(this.map, { //智能搜索
+	      onSearchComplete
+	    });
+
+	    local.search(this.value);
+    },
+    initValue(){
+      if(this.toponym) return
+      this.value = this.toponym
+      this.setPlace()
+    },
+    save(){
+      console.log(this.point,this.value)
+      if(this.point.length !== 2 || !this.value){
+        this.$message.warning('请选择地址')
+        return
+      }
+
+      this.$emit('save',{ point:this.point, name:this.value })
+      this._visible = false
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+#l-map{
+  width: 100%;
+  height: 300px;
+}
+
+#r-result{
+  width: 100%;
+  height: 34px;
+  margin-bottom: 20px;
+  font-size: 16px;
+  display: flex;
+  align-items: center;
+
+  p{
+    width:60px;
+  }
+
+  input {
+    border:1px solid #DCDFE6;
+    width: 100%;
+    height: 100%;
+    border-radius: 5px;
+    box-sizing: border-box;
+    padding: 5px;
+  }
+}
+</style>

+ 3 - 0
src/views/operate/shop/detail.vue

@@ -23,6 +23,7 @@
           />
         </el-tab-pane>
       </el-tabs>
+
     </div>
     <div v-else>
       <no-auth></no-auth>
@@ -34,6 +35,7 @@ import asyncRequest from "@/apis/service/operate/shop";
 import resToken from "@/mixins/resToken";
 import { mapGetters } from "vuex";
 import baseForm from "./components/baseForm";
+
 export default {
   name: "shopDetail",
   mixins: [resToken],
@@ -52,6 +54,7 @@ export default {
 
   data() {
     return {
+      visible: false,
       title: "供应商店铺",
       size: "small",
       activeTabs: "1",