Kaynağa Gözat

feat: 增加报价记录交互. 增加向crm转单交互(创建SO).

peter 4 ay önce
ebeveyn
işleme
f748737310

+ 16 - 0
src/api/indent.js

@@ -120,3 +120,19 @@ export const setDefaultQuote = (data) =>
     method: 'post',
     data,
   })
+
+// 计价导出的记录. 转单 界面列表数据
+export const getCalcPriceRecord = (data) =>
+  request({
+    url: '/indent_change/getList',
+    method: 'post',
+    data,
+  })
+
+// 向crm转单
+export const generateOrder = (data) =>
+  request({
+    url: '/indent_change/updatechange',
+    method: 'post',
+    data,
+  })

+ 141 - 0
src/pages/indent-manage/indent/components/quoteRecord.vue

@@ -0,0 +1,141 @@
+<template>
+  <div class="dialog-change-order">
+    <el-dialog
+      v-model="show"
+      class="custom-apply-sku-dialog"
+      title="报价记录"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      :before-close="close"
+      width="1200px"
+    >
+      <el-table
+        v-loading="loading"
+        :data="list"
+      >
+        <el-table-column
+          label="序号"
+          width="80"
+          type="index"
+        ></el-table-column>
+        <el-table-column
+          width="180"
+          label="Items"
+          prop="items"
+        ></el-table-column>
+        <el-table-column
+          label="采购数量"
+          prop="number"
+        ></el-table-column>
+        <el-table-column
+          label="售价"
+          prop="unit_cost"
+        ></el-table-column>
+        <el-table-column
+          label="setup"
+          prop="setup_cost"
+        ></el-table-column>
+        <el-table-column
+          label="运费"
+          prop="freight"
+        ></el-table-column>
+        <el-table-column
+          width="180"
+          label="创建时间"
+          prop="create_time"
+        ></el-table-column>
+        <el-table-column label="操作">
+          <template #default="scope">
+            <el-button
+              size="small"
+              type="primary"
+              plain
+              @click="onChangeOrderClick(scope.row)"
+            >
+              转单
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="my-4 flex justify-end">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          v-model:total="total"
+          layout="prev, pager, next, jumper, sizes"
+          :page-sizes="[10, 20, 50, 100]"
+          @current-change="getCalcPriceRecordFunc"
+          @size-change="getCalcPriceRecordFunc"
+        ></el-pagination>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script lang="ts" setup>
+import { defineComponent, ref, watch } from 'vue'
+import {
+  ElDialog,
+  ElButton,
+  ElTable,
+  ElTableColumn,
+  ElNotification,
+  ElPagination,
+  ElMessage,
+} from 'element-plus'
+import { getCalcPriceRecord, generateOrder } from '@/api/indent'
+defineComponent({
+  name: 'ComponentQuoteRecord',
+})
+const { visible = false, id = '' } = defineProps<{
+  visible: boolean
+  id: string | number
+}>()
+const $emit = defineEmits(['update:visible'])
+let show = ref(false)
+let loading = ref(false)
+let list = ref([] as any[])
+
+watch(
+  () => visible,
+  () => {
+    show.value = visible
+    if (show.value) {
+      getCalcPriceRecordFunc()
+    }
+  },
+)
+
+const pageSize = ref(10)
+const currentPage = ref(1)
+const total = ref(0)
+
+const getCalcPriceRecordFunc = () => {
+  loading.value = true
+  getCalcPriceRecord({ id: id })
+    .then((res: any) => {
+      if (res.code === 1) list.value = res.result.data || []
+    })
+    .finally(() => (loading.value = false))
+}
+let close = (done = {} as any) => {
+  $emit('update:visible', false)
+  if (typeof done === 'function') done()
+}
+
+const onChangeOrderClick = (row: any) => {
+  loading.value = true
+  generateOrder({ id: row.id })
+    .then((res: any) => {
+      if (res.code === 1) {
+        ElMessage.success('转单成功')
+      } else {
+        ElNotification({
+          title: '转单失败',
+          message: res.message + ', ' + row.toString(),
+        })
+      }
+    })
+    .finally(() => (loading.value = false))
+}
+</script>
+<style lang="scss"></style>

+ 28 - 0
src/pages/indent-manage/indent/list.vue

@@ -257,18 +257,22 @@
             >
               <template #default="scope">
                 <el-button
+                  size="small"
                   type="warning"
                   @click="editInfo(scope.row)"
                 >
                   {{ $t('btn_edit') }}
                 </el-button>
                 <el-button
+                  size="small"
                   type="primary"
                   @click="valuation(scope.row)"
                 >
                   {{ $t(prefix + 'btn_calc_price') }}
                 </el-button>
                 <el-button
+                  v-if="props.row.default_quote !== scope.row.id"
+                  size="small"
                   type="success"
                   :disabled="props.row.default_quote === scope.row.id"
                   @click="adopt(scope.row, props.row)"
@@ -279,6 +283,14 @@
                       : $t(prefix + 'btn_adopt')
                   }}
                 </el-button>
+                <el-button
+                  v-if="props.row.default_quote === scope.row.id"
+                  size="small"
+                  type="warning"
+                  @click="onBtnChangeOrderClick(scope.row)"
+                >
+                  转单
+                </el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -391,6 +403,10 @@
         />
       </div>
     </el-dialog>
+    <dialogQuoteRecord
+      :id="changeOrderID"
+      v-model:visible="dialogChangeOrderVisible"
+    ></dialogQuoteRecord>
   </div>
 </template>
 
@@ -425,6 +441,7 @@ import edit from './edit.vue'
 import freight from './components/freight.vue'
 import compEditInfo from './components/info.vue'
 import calcPrice from './components/calcPrice/index.vue'
+import dialogQuoteRecord from './components/quoteRecord.vue'
 
 defineComponent({
   name: 'PageIndentList',
@@ -922,6 +939,17 @@ const imgClick = (url: string) => {
 watch(bigImageVisible, () => {
   if (!bigImageVisible.value) currentBigImage.value = ''
 })
+
+const changeOrderID = ref('')
+const dialogChangeOrderVisible = ref(false)
+const onBtnChangeOrderClick = (row: any) => {
+  console.log('row')
+  changeOrderID.value = row.id
+  dialogChangeOrderVisible.value = true
+}
+watch(dialogChangeOrderVisible, () => {
+  if (!dialogChangeOrderVisible.value) changeOrderID.value = ''
+})
 </script>
 
 <style lang="scss">

+ 1 - 1
src/pages/indent-manage/product/components/edit.vue

@@ -110,7 +110,7 @@
             <el-input v-model="form.size"></el-input>
           </el-form-item>
           <el-form-item
-            style="align-items: flex-start;"
+            style="align-items: flex-start"
             label="关键词"
             prop="keywords"
           >

+ 251 - 91
src/pages/indent-manage/product/components/examine.vue

@@ -6,81 +6,154 @@
       :close-on-click-modal="false"
       :close-on-press-escape="false"
       :before-close="close"
-      width="550px"
+      width="820px"
     >
       <el-form
         ref="formRef"
         v-loading="loading"
-        style="width: 500px"
+        style="width: 780px"
         :rules="rules"
         :model="form"
         label-width="110px"
       >
-        <el-form-item
-          :label="$t(prefix + 'label_name')"
-          prop=""
-        >
-          <div>{{ form.product_name }}</div>
-        </el-form-item>
-        <el-form-item
-          label="中文品名"
-          prop=""
-        >
-          <div>{{ form.product_name_cn }}</div>
-        </el-form-item>
-        <el-form-item
-          :label="$t(prefix + 'label_audit')"
-          prop=""
-        >
-          <el-radio-group
-            v-model="form.status"
-            @change="formRef!.clearValidate('product_sku')"
-          >
-            <el-radio :label="1">审核通过</el-radio>
-            <el-radio :label="2">审核不通过</el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item
-          :label="$t(prefix + 'label_category')"
-          prop="category_id"
-        >
-          <el-cascader
-            v-model="form.category_id"
-            style="width: 410px"
-            :options="categoryData"
-            :props="{ label: 'name', value: 'id' }"
-          ></el-cascader>
-        </el-form-item>
-        <el-form-item
-          label="SKU"
-          prop="product_sku"
-        >
-          <el-input v-model="form.product_sku" />
-        </el-form-item>
-        <el-form-item
-          :label="$t(prefix + 'label_feedback')"
-          prop="feedback"
-        >
-          <el-input
-            v-model="form.feedback"
-            type="textarea"
-            :rows="5"
-          ></el-input>
-        </el-form-item>
+        <div class="flex justify-between flex-wrap">
+          <el-form-item
+            :label="$t(prefix + 'label_category')"
+            prop="category_id"
+          >
+            <el-cascader
+              v-model="form.category_id"
+              style="width: 410px"
+              :options="categoryData"
+              :props="{ label: 'name', value: 'id' }"
+            ></el-cascader>
+          </el-form-item>
+          <el-form-item
+            :label="$t(prefix + 'label_name_en')"
+            prop="product_name"
+          >
+            <el-input
+              v-model="form.product_name"
+              disabled
+            ></el-input>
+          </el-form-item>
+          <el-form-item
+            :label="$t(prefix + 'label_name_cn')"
+            prop="product_name_cn"
+          >
+            <el-input
+              v-model="form.product_name_cn"
+              disabled
+            ></el-input>
+          </el-form-item>
+          <el-form-item
+            label="Primary SKU"
+            prop="product_sku"
+          >
+            <el-input v-model="form.product_sku"></el-input>
+          </el-form-item>
+          <el-form-item
+            label="Primary Code"
+            prop="product_code"
+          >
+            <el-input v-model="form.product_code"></el-input>
+          </el-form-item>
+          <el-form-item
+            label="SKU"
+            prop="sku"
+          >
+            <el-input v-model="form.sku"></el-input>
+          </el-form-item>
+          <el-form-item
+            label="entity"
+            prop="entity"
+          >
+            <el-input v-model="form.entity"></el-input>
+          </el-form-item>
+          <el-form-item
+            label="product_type"
+            prop="product_type"
+          >
+            <el-select v-model="form.product_type">
+              <el-option value="Express"></el-option>
+              <el-option value="indent"></el-option>
+              <el-option value="Stock"></el-option>
+              <el-option value="Other"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item
+            label="Classification"
+            prop="classification"
+          >
+            <el-select v-model="form.classification">
+              <el-option value="Promo Collection"></el-option>
+              <el-option value="Primepac"></el-option>
+              <el-option value="Phoenixexhibit"></el-option>
+              <el-option value="Material"></el-option>
+              <el-option value="Test purpose"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item
+            label="材质"
+            prop="material"
+          >
+            <el-input v-model="form.material"></el-input>
+          </el-form-item>
+          <el-form-item
+            label="颜色"
+            prop="colour"
+          >
+            <el-input v-model="form.colour"></el-input>
+          </el-form-item>
+          <el-form-item
+            label="尺寸"
+            prop="size"
+          >
+            <el-input v-model="form.size"></el-input>
+          </el-form-item>
+          <el-form-item
+            style="align-items: flex-start"
+            label="关键词"
+            prop="keywords"
+          >
+            <el-input
+              v-model="form.keywords"
+              type="textarea"
+              :rows="3"
+            ></el-input>
+          </el-form-item>
+          <el-form-item :label="$t(prefix + 'lable_image_list')">
+            <image-upload
+              v-model:list="imageList"
+              :disable-preview="true"
+            ></image-upload>
+          </el-form-item>
+          <el-form-item
+            :label="$t(prefix + 'label_feedback')"
+            prop="feedback"
+          >
+            <el-input
+              v-model="form.feedback"
+              type="textarea"
+              :rows="5"
+            ></el-input>
+            <div class="text-red-500 text-base leading-5">
+              驳回填一下反馈详情直接点驳回就行, 不用管标红的必填项
+            </div>
+          </el-form-item>
+        </div>
       </el-form>
       <template #footer>
         <div class="flex justify-center items-center">
           <el-button
             type="danger"
-            size="small"
-            @click="checkForm(2)"
+            @click="checkForm2()"
           >
             驳回
           </el-button>
           <el-button
-            size="small"
             type="primary"
-            @click="checkForm(1)"
+            @click="checkForm()"
           >
             审核通过
           </el-button>
@@ -90,10 +163,12 @@
   </div>
 </template>
 <script lang="ts" setup>
-import { defineComponent, ref, watch } from 'vue'
+import { defineComponent, ref, watch, nextTick, inject } from 'vue'
 import {
-  ElRadio,
-  ElRadioGroup,
+  // ElRadio,
+  // ElRadioGroup,
+  ElSelect,
+  ElOption,
   ElDialog,
   ElButton,
   ElForm,
@@ -105,7 +180,9 @@ import {
 import type { FormInstance } from 'element-plus'
 import cloneDeep from 'lodash.clonedeep'
 import { $t } from '@/i18n/index'
-import { saveExamine } from '@/api/product'
+import { saveExamine, updateProduct } from '@/api/product'
+import imageUpload from '@/components/ImageUpload.vue'
+
 defineComponent({
   name: 'DialogExamineRecord',
 })
@@ -120,6 +197,7 @@ const {
   categoryData: any[]
 }>()
 
+const $mediaRegExp = inject('mediaRegExp') as RegExp
 const prefix = 'order.product.'
 let show = ref(false)
 let loading = ref(false)
@@ -130,22 +208,31 @@ const form = ref({
   product_sku: '',
   category_id: [],
   images: '',
-  status: 1,
+  status: 0,
 } as any)
-
-const checkSKU = (rule: any, value: any, cb: any) => {
-  if (form.value.status !== 1) {
-    cb()
-  } else {
-    if (!value) {
-      cb(new Error($t('text_please_input')))
-    } else {
-      cb()
-    }
-  }
-}
+const imageList = ref([] as any[])
 const rules = {
-  product_sku: [{ required: true, validator: checkSKU, trigger: 'change' }],
+  product_name: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
+  product_name_cn: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
+  product_sku: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
   category_id: [
     {
       required: true,
@@ -153,6 +240,41 @@ const rules = {
       trigger: 'change',
     },
   ],
+  product_code: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
+  colour: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
+  material: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
+  size: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
+  sku: [
+    {
+      required: true,
+      message: $t('text_please_input'),
+      trigger: 'change',
+    },
+  ],
 }
 
 watch(
@@ -176,6 +298,17 @@ watch(
       delete form.value.admin_id
       delete form.value.create_time
       delete form.value.update_time
+      nextTick(() => {
+        if (!(Array.isArray(form.value.images) && form.value.images.length))
+          return
+        imageList.value = form.value.images.map((img: string) => {
+          return {
+            url: $mediaRegExp.test(img)
+              ? img
+              : import.meta.env.VITE_APP_OSS_PREFIX + img,
+          }
+        })
+      })
     }
   },
 )
@@ -210,39 +343,66 @@ const getCategory = (id: number | string) => {
 
   return result
 }
-/**
- * flag 2 驳回. 其他通过.
- */
-const checkForm = (flag: number) => {
+
+const checkForm = () => {
   if (!formRef.value) return
   formRef.value.validate((valid) => {
     if (valid) {
       const p = cloneDeep(form.value)
-
+      p.images = imageList.value
+        .map((i) => {
+          return i.url.replace($mediaRegExp, '/')
+        })
+        .join(',')
       p.category_id = p.category_id[p.category_id.length - 1].toString()
-      p.status = flag
+      p.status = 1
       p.product_id = p.id
-      delete p.product_name
-      delete p.product_name_cn
-      delete p.images
 
       saveExamine(p).then((res: any) => {
         if (res.code === 1) {
-          ElNotification({
-            title: '操作成功',
-            message: '正在刷新数据',
-            duration: 3000,
+          delete p.feedback
+          delete p.product_id
+          updateProduct(p).then(() => {
+            ElNotification({
+              title: '操作成功',
+              message: '正在刷新数据',
+              duration: 3000,
+            })
+            close()
           })
-          close()
         }
       })
     }
   })
 }
+const checkForm2 = () => {
+  const temp = cloneDeep(form.value)
+  const p = {
+    status: 2,
+    id: temp.id,
+    feedback: temp.feedback || '',
+    product_sku: temp.product_sku,
+    product_id: temp.id,
+  }
+  saveExamine(p).then((res: any) => {
+    if (res.code === 1) {
+      ElNotification({
+        title: '操作成功',
+        message: '正在刷新数据',
+        duration: 3000,
+      })
+      close()
+    }
+  })
+}
 let close = (done = {} as any) => {
-  $emit('update:visible', 0)
+  $emit('update:visible', false)
   if (typeof done === 'function') done()
 }
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.el-form-item {
+  width: 48%;
+}
+</style>

+ 2 - 2
src/pages/indent-manage/product/components/record.vue

@@ -63,7 +63,7 @@ watch(
   () => visible,
   () => {
     show.value = visible
-    if (show.value) getRecord
+    if (show.value) getRecord()
   },
 )
 
@@ -89,7 +89,7 @@ const getRecord = () => {
 }
 
 let close = (done = {} as any) => {
-  $emit('update:visible', 0)
+  $emit('update:visible', false)
   if (typeof done === 'function') done()
 }
 </script>

+ 1 - 5
src/pages/indent-manage/user/edit.vue

@@ -81,7 +81,7 @@
           multiple
         ></el-select-v2>
       </el-form-item>
-      <!-- <el-form-item> -->
+
       <div class="flex justify-center w-[100%] mt-8">
         <el-button
           type="primary"
@@ -91,7 +91,6 @@
         </el-button>
         <el-button @click="close">取消</el-button>
       </div>
-      <!-- </el-form-item> -->
     </el-form>
   </el-dialog>
 </template>
@@ -100,7 +99,6 @@ import {
   defineComponent,
   ref,
   watch,
-  computed,
   defineProps,
   defineEmits,
   nextTick,
@@ -116,8 +114,6 @@ import {
   ElMessage,
 } from 'element-plus'
 import type { FormInstance } from 'element-plus'
-import { CirclePlus } from '@element-plus/icons-vue'
-import debounce from 'lodash.debounce'
 import cloneDeep from 'lodash.clonedeep'
 import { $t } from '@/i18n/index'
 import userAPI from '@/api/user'