li.shaoyi 2 лет назад
Родитель
Сommit
ef70bce602
23 измененных файлов с 407 добавлено и 90 удалено
  1. 25 11
      src/constants/regex.ts
  2. 5 5
      src/mock/router.ts
  3. 3 6
      src/packages/pc/views/bonded/inbound/components/apply/index.vue
  4. 3 6
      src/packages/pc/views/bonded/outbound/components/apply/index.vue
  5. 101 0
      src/packages/pc/views/centralize/list/components/buy/index.vue
  6. 144 0
      src/packages/pc/views/centralize/list/components/details/index.vue
  7. 15 9
      src/packages/pc/views/centralize/mine/components/add/index.vue
  8. 7 4
      src/packages/pc/views/centralize/mine/components/add/price-edit.vue
  9. 17 1
      src/packages/pc/views/centralize/mine/components/details/index.vue
  10. 2 2
      src/packages/pc/views/centralize/partake/components/details/index.vue
  11. 1 7
      src/packages/pc/views/centralize/partake/index.vue
  12. 5 11
      src/packages/pc/views/customs/exit/components/edit/index.vue
  13. 26 5
      src/packages/pc/views/presale/list/components/buy/index.vue
  14. 4 1
      src/packages/pc/views/presale/list/components/details/index.vue
  15. 15 9
      src/packages/pc/views/presale/mine/components/add/index.vue
  16. 2 2
      src/packages/pc/views/presale/partake/components/details/index.vue
  17. 1 7
      src/packages/pc/views/presale/partake/index.vue
  18. 1 1
      src/packages/pc/views/trade/buy/components/delisting/index.vue
  19. 1 1
      src/packages/pc/views/warehousing/goods/components/bargain/index.vue
  20. 10 0
      src/services/api/presale/index.ts
  21. 1 1
      src/services/socket/trade/interface.ts
  22. 17 0
      src/types/ermcp/presale.d.ts
  23. 1 1
      src/types/proto/presale.d.ts

+ 25 - 11
src/constants/regex.ts

@@ -1,33 +1,47 @@
-/**
- * 表单验证规则
- */
-export const validateRules = {
+// 表单验证规则
+export const regular = {
     password: {
-        validate: (val: string) => /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)])+$)^.{6,64}$/.test(val),
+        reg: /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)])+$)^.{6,64}$/,
         message: '密码必须包含字母、数字、特殊符号中的任意两种组合,长度最少6位',
     },
     phone: {
-        validate: (val: string) => /^$|^1[3456789]\d{9}$/.test(val),
+        reg: /^$|^1[3456789]\d{9}$/,
         message: '手机号码无效',
     },
     email: {
-        validate: (val: string) => /^$|^([a-zA-Z]|[0-9])(\w)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(val),
+        reg: /^$|^([a-zA-Z]|[0-9])(\w)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/,
         message: '邮箱地址无效',
     },
     en: {
-        validate: (val: string) => /^[A-Za-z]+$/.test(val),
+        reg: /^[A-Za-z]+$/,
         message: '只能输入英文字母(不允许空格)',
     },
     enname: {
-        validate: (val: string) => /^[a-zA-Z0-9_]{1,}$/.test(val),
+        reg: /^[a-zA-Z0-9_]{1,}$/,
         message: '只能输入英文字母、数字、下划线',
     },
     cardno: {
-        validate: (val: string) => /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(val),
+        reg: /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
         message: '身份证号码不合规',
     },
     bankcardno: {
-        validate: (val: string) => /^([1-9]{1})(\d{15}|\d{16}|\d{18})$/.test(val),
+        reg: /^([1-9]{1})(\d{15}|\d{16}|\d{18})$/,
         message: '银行卡号码不合规',
+    },
+    integer: {
+        reg: /^[1-9]\d*$/,
+        message: '只能输入大于0的正整数',
+    },
+    positive: {
+        reg: /^([1-9]\d*)(\.\d{1,6})?$|^0\.\d{1,6}?$/,
+        message: '只能输入大于0的数值',
+    }
+}
+
+export function validate<T extends keyof typeof regular>(value: string, type: T, error?: string) {
+    const { reg, message } = regular[type]
+    if (reg.test(value)) {
+        return ''
     }
+    return error ?? message
 }

+ 5 - 5
src/mock/router.ts

@@ -335,7 +335,7 @@ const appmenu = {
             {
                 authType: 1,
                 sort: 5,
-                title: '集交易',
+                title: '集交易',
                 code: 'centralize',
                 url: '/centralize',
                 urlType: 1,
@@ -345,7 +345,7 @@ const appmenu = {
                     {
                         authType: 1,
                         sort: 1,
-                        title: '集大厅',
+                        title: '集大厅',
                         code: 'centralize_list',
                         url: '',
                         urlType: 1,
@@ -362,7 +362,7 @@ const appmenu = {
                     {
                         authType: 1,
                         sort: 2,
-                        title: '我的集',
+                        title: '我的集',
                         code: 'centralize_mine',
                         url: 'mine',
                         urlType: 1,
@@ -370,7 +370,7 @@ const appmenu = {
                         children: [
                             {
                                 authType: 3,
-                                title: '集申请',
+                                title: '集申请',
                                 code: 'centralize_mine_add',
                                 component: 'views/centralize/mine/components/add/index.vue',
                                 className: 'el-button--primary',
@@ -393,7 +393,7 @@ const appmenu = {
                     {
                         authType: 1,
                         sort: 3,
-                        title: '我参与的集',
+                        title: '我参与的集',
                         code: 'centralize_partake',
                         url: 'partake',
                         urlType: 1,

+ 3 - 6
src/packages/pc/views/bonded/inbound/components/apply/index.vue

@@ -53,7 +53,7 @@
 import { shallowRef, ref, defineAsyncComponent } from 'vue'
 import { ElMessage } from 'element-plus'
 import type { FormInstance, FormRules } from 'element-plus'
-import { validateRules } from '@/constants/regex'
+import { validate } from '@/constants/regex'
 import { GZBSCOrderType } from '@/constants/bonded'
 import { useBscInAndOutWareHouseApply } from '@/business/bonded'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
@@ -104,11 +104,8 @@ const formRules: FormRules = {
         trigger: 'blur',
         validator: (rule, value, callback) => {
             if (value) {
-                if (validateRules.phone.validate(value)) {
-                    callback()
-                } else {
-                    callback(new Error(validateRules.phone.message))
-                }
+                const message = validate(value, 'phone')
+                message ? callback(new Error(message)) : callback()
             } else {
                 callback(new Error('请输入联系电话'))
             }

+ 3 - 6
src/packages/pc/views/bonded/outbound/components/apply/index.vue

@@ -79,7 +79,7 @@ import { shallowRef, ref, defineAsyncComponent } from 'vue'
 import { ElMessage } from 'element-plus'
 import type { FormInstance, FormRules } from 'element-plus'
 import { useComponent } from '@/hooks/component'
-import { validateRules } from '@/constants/regex'
+import { validate } from '@/constants/regex'
 import { getGZBSCOutTypeList } from '@/constants/bonded'
 import { GZBSCOrderType } from '@/constants/bonded'
 import { useBscInAndOutWareHouseApply } from '@/business/bonded'
@@ -148,11 +148,8 @@ const formRules: FormRules = {
         trigger: 'blur',
         validator: (rule, value, callback) => {
             if (value) {
-                if (validateRules.phone.validate(value)) {
-                    callback()
-                } else {
-                    callback(new Error(validateRules.phone.message))
-                }
+                const message = validate(value, 'phone')
+                message ? callback(new Error(message)) : callback()
             } else {
                 callback(new Error('请输入联系电话'))
             }

+ 101 - 0
src/packages/pc/views/centralize/list/components/buy/index.vue

@@ -0,0 +1,101 @@
+<!-- 集采交易-预售大厅-认购 -->
+<template>
+    <app-drawer title="认购" v-model:show="show" :loading="loading" :refresh="refresh">
+        <el-form ref="formRef" label-width="100px" :model="formData" :rules="formRules">
+            <el-form-item label="商品名称">
+                {{ selectedRow.wrstandardname }}
+            </el-form-item>
+            <el-form-item label="最小采购单位">
+                {{ selectedRow.minbuyqty }}
+            </el-form-item>
+            <el-form-item label="最大采购单位">
+                {{ selectedRow.maxbuyqty }}
+            </el-form-item>
+            <el-form-item label="剩余集采量">
+                {{ remainqty }}
+            </el-form-item>
+            <el-form-item label="采购数量" prop="OrderQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.OrderQty">
+                    <template #append>(克拉)</template>
+                </el-input>
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, reactive, PropType, computed } from 'vue'
+import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { validate } from '@/constants/regex'
+import { gzCenterPurchaseOrder } from '@/services/api/presale'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import Long from 'long'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZPreSellRsp>,
+        required: true
+    },
+})
+
+const formRef = shallowRef<FormInstance>()
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+
+const formData = reactive<Partial<Proto.GZCenterPurchaseOrderReq>>({
+    WRTradeOrderID: Long.fromString(props.selectedRow.sellwrtradeorderid), // 仓单贸易委托单ID,必填
+})
+
+// 剩余预售量
+const remainqty = computed(() => props.selectedRow.presaleqty - props.selectedRow.tradeqty)
+
+const formRules: FormRules = {
+    OrderQty: [{
+        required: true,
+        validator: (rule, value, callback) => {
+            const message = validate(value, 'integer')
+            if (message) {
+                callback(new Error('请输入采购数量'))
+            } else {
+                const { minbuyqty, maxbuyqty } = props.selectedRow
+                const qty = Number(value)
+                if (qty > remainqty.value) {
+                    callback(new Error('剩余数量不足'))
+                } else if (qty < minbuyqty) {
+                    callback(new Error('数量不能小于' + minbuyqty))
+                } else if (qty > maxbuyqty) {
+                    callback(new Error('数量不能大于' + maxbuyqty))
+                } else {
+                    callback()
+                }
+            }
+        }
+    }],
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            loading.value = true
+            gzCenterPurchaseOrder(formData).then(() => {
+                ElMessage.success('提交成功')
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error('提交失败:' + err)
+            }).finally(() => {
+                loading.value = false
+            })
+        }
+    })
+}
+</script>

+ 144 - 0
src/packages/pc/views/centralize/list/components/details/index.vue

@@ -0,0 +1,144 @@
+<!-- 集采交易-预售大厅-详情 -->
+<template>
+    <app-drawer title="详情" :width="800" v-model:show="show" :loading="loading" :refresh="refresh">
+        <app-table-details title="集采信息" :label-width="140" :data="selectedRow" :cell-props="details1" :column="2">
+            <!-- 采购保证金比例 -->
+            <template #buymarginvalue="{ value }">
+                {{ parsePercent(value) }}
+            </template>
+            <!-- 状态 -->
+            <template #presalestatus="{ value }">
+                {{ getWRPresaleStatusName(value) }}
+            </template>
+            <!-- 履约方式 -->
+            <template #performancetemplateid="{ value }">
+                <app-performance-rule :item="getPerformanceTemplateById(value)" />
+            </template>
+            <!-- 集采价格 -->
+            <template #price>
+                <app-table :data="priceList" :columns="priceColumns" :show-toolbar="false" border />
+            </template>
+        </app-table-details>
+        <app-table-details title="钻石参考信息" :label-width="140" :data="selectedRow" :cell-props="details2" :column="2">
+            <!-- 生产方式 -->
+            <template #ysproductionmode="{ value }">
+                {{ getYSProductionModeName(value) }}
+            </template>
+            <!-- 图片 -->
+            <template #pictureurls>
+                <template v-for="(url, index) in imageUrl" :key="index">
+                    <el-image :src="url" :preview-src-list="imageUrl" fit="cover" />
+                </template>
+            </template>
+        </app-table-details>
+        <template #footer v-if="selectedRow.presalestatus !== 1">
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="showBuy = true">认购</el-button>
+        </template>
+        <component :is="Buy" v-bind="{ selectedRow }" @closed="onBuyClosed" v-if="showBuy" />
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, reactive, PropType, onMounted, defineAsyncComponent } from 'vue'
+import { getFileUrl, parsePercent } from '@/filters'
+import { getWRPresaleStatusName, getYSProductionModeName } from '@/constants/presale'
+import { useRequest } from '@/hooks/request'
+import { queryPresaleorderapplyprice } from '@/services/api/presale'
+import { performanceStore } from '@/stores'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppTable from '@pc/components/base/table/index.vue'
+import AppTableDetails from '@pc/components/base/table-details/index.vue'
+import AppPerformanceRule from '@pc/components/modules/performance-rule/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Ermcp.GZPreSellRsp>,
+        required: true
+    },
+})
+
+// 认购
+const Buy = defineAsyncComponent(() => import('../buy/index.vue'))
+
+const { getPerformanceTemplateById } = performanceStore.actions
+const show = shallowRef(true)
+const showBuy = shallowRef(false)
+const refresh = shallowRef(false)
+const loading = shallowRef(false)
+const imageUrl = reactive<string[]>([])
+
+const { dataList: priceList } = useRequest(queryPresaleorderapplyprice, {
+    params: {
+        applyid: props.selectedRow.presaleapplyid
+    }
+})
+
+const details1 = [
+    { prop: 'wrstandardname', label: '商品名称:' },
+    { prop: 'customername', label: '卖方:' },
+    { prop: 'presaleqty', label: '集采总量:' },
+    { prop: 'yszscategory', label: '钻石类型:' },
+    { prop: 'minbuyqty', label: '最小采购单位:' },
+    { prop: 'minsuccessqty', label: '最低成团量:' },
+    { prop: 'maxbuyqty', label: '最大采购单位:' },
+    { prop: 'buymarginvalue', label: '采购保证金比例:' },
+    { prop: 'startdate', label: '开始日期:' },
+    { prop: 'enddate', label: '结束日期:' },
+    { prop: 'presalestatus', label: '状态:' },
+    { prop: 'tradeqty', label: '已采购数量:' },
+    { prop: 'performancetemplateid', label: '履约方式:', entireRow: true },
+    { prop: 'price', label: '集采价格:', entireRow: true },
+]
+
+const details2 = [
+    { prop: 'zscolortypestr', label: '颜色:' },
+    { prop: 'sizestr', label: '尺寸:' },
+    { prop: 'zsclaritytypestr', label: '净度:' },
+    { prop: 'yieldrate', label: '成品率:' },
+    { prop: 'qtydesc', label: '数量描述:' },
+    { prop: 'weightdesc', label: '重量描述:' },
+    { prop: 'ysproductionmode', label: '生产方式:' },
+    { prop: 'pictureurls', label: '图片:', entireRow: true },
+    { prop: 'remark', label: '备注:', entireRow: true },
+]
+
+const priceColumns: Ermcp.TableColumn[] = [
+    { prop: 'stepindex', label: '序号' },
+    { prop: 'qty', label: '数量' },
+    { prop: 'price', label: '价格(元/克拉)' },
+]
+
+const onBuyClosed = (isRefresh = false) => {
+    showBuy.value = false
+    if (isRefresh) {
+        onCancel(true)
+    }
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+onMounted(() => {
+    const images = props.selectedRow.pictureurls.split(',')
+    images.forEach((url) => {
+        if (url) {
+            imageUrl.push(getFileUrl(url))
+        }
+    })
+})
+</script>
+
+<style lang="less" scoped>
+.el-image {
+    width: 64px;
+    height: 64px;
+    border: 1px solid #ccc;
+
+    +.el-image {
+        margin-left: 10px;
+    }
+}
+</style>

+ 15 - 9
src/packages/pc/views/centralize/mine/components/add/index.vue

@@ -14,7 +14,7 @@
                 </el-radio-group>
             </el-form-item>
             <el-form-item label="集采数量" prop="PresaleQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.PresaleQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.PresaleQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
@@ -22,17 +22,17 @@
                 <component :is="PerformanceTemplate" v-model="formData.PerformanceTemplateID" />
             </el-form-item>
             <el-form-item label="最小采购单位" prop="MinBuyQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.MinBuyQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.MinBuyQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
             <el-form-item label="最低成团量" prop="MinSuccessQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.MinSuccessQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.MinSuccessQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
             <el-form-item label="最大采购单位" prop="MaxBuyQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.MaxBuyQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.MaxBuyQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
@@ -108,6 +108,7 @@
 import { ref, reactive, defineAsyncComponent } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { formatDate } from '@/filters'
+import { regular } from '@/constants/regex'
 import { getYSProductionModeList, getYSZSCategoryList } from '@/constants/presale'
 import { gzCenterPurchaseApply } from '@/services/api/presale'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
@@ -154,23 +155,28 @@ const formRules: FormRules = {
     }],
     PresaleQty: [{
         required: true,
-        message: '请输入集采数量'
+        message: '请输入集采数量',
+        pattern: regular.integer.reg
     }],
     MinBuyQty: [{
         required: true,
-        message: '请输入最小采购单位'
+        message: '请输入最小采购单位',
+        pattern: regular.integer.reg
     }],
     MinSuccessQty: [{
         required: true,
-        message: '请输入最低成团量'
+        message: '请输入最低成团量',
+        pattern: regular.integer.reg
     }],
     MaxBuyQty: [{
         required: true,
-        message: '请输入最大采购单位'
+        message: '请输入最大采购单位',
+        pattern: regular.integer.reg
     }],
     BuyMarginValue: [{
         required: true,
-        message: '请输入采购保证金比例'
+        message: '请输入采购保证金比例',
+        pattern: regular.positive.reg
     }],
     PreDate: [{
         required: true,

+ 7 - 4
src/packages/pc/views/centralize/mine/components/add/price-edit.vue

@@ -3,10 +3,10 @@
     <app-drawer title="编辑" :width="400" v-model:show="show">
         <el-form ref="formRef" label-width="60px" :model="formItem" :rules="formRules">
             <el-form-item label="数量" prop="Qty">
-                <el-input-number placeholder="请输入" v-model="formItem.Qty" />
+                <el-input-number placeholder="请输入" :min="0" :precision="0" v-model="formItem.Qty" />
             </el-form-item>
             <el-form-item label="价格" prop="Price">
-                <el-input-number placeholder="请输入" v-model="formItem.Price" />
+                <el-input-number placeholder="请输入" :min="0" v-model="formItem.Price" />
             </el-form-item>
         </el-form>
         <template #footer>
@@ -19,6 +19,7 @@
 <script lang="ts" setup>
 import { ref, PropType } from 'vue'
 import type { FormInstance, FormRules } from 'element-plus'
+import { regular } from '@/constants/regex'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 
 const props = defineProps({
@@ -35,11 +36,13 @@ const formItem = ref<Partial<Proto.GZCenterPurchasePrice>>({ StepIndex: 0, ...pr
 const formRules: FormRules = {
     Qty: [{
         required: true,
-        message: '请输入数量'
+        message: '请输入数量',
+        pattern: regular.integer.reg
     }],
     Price: [{
         required: true,
-        message: '请输入价格'
+        message: '请输入价格',
+        pattern: regular.positive.reg
     }],
 }
 

+ 17 - 1
src/packages/pc/views/centralize/mine/components/details/index.vue

@@ -14,6 +14,10 @@
             <template #performancetemplateid="{ value }">
                 <app-performance-rule :item="getPerformanceTemplateById(value)" />
             </template>
+            <!-- 集采价格 -->
+            <template #price>
+                <app-table :data="priceList" :columns="priceColumns" :show-toolbar="false" border />
+            </template>
         </app-table-details>
         <app-table-details title="钻石参考信息" :label-width="140" :data="selectedRow" :cell-props="details2" :column="2">
             <!-- 生产方式 -->
@@ -45,7 +49,7 @@ import { getFileUrl, parsePercent } from '@/filters'
 import { getWRPresaleStatusName, getYSProductionModeName } from '@/constants/presale'
 import { useRequest } from '@/hooks/request'
 import { performanceStore } from '@/stores'
-import { queryGZMyPresell } from '@/services/api/presale'
+import { queryGZMyPresell, queryPresaleorderapplyprice } from '@/services/api/presale'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import AppTable from '@pc/components/base/table/index.vue'
 import AppPagination from '@pc/components/base/pagination/index.vue'
@@ -63,6 +67,12 @@ const { getPerformanceTemplateById } = performanceStore.actions
 const show = shallowRef(true)
 const imageUrl = reactive<string[]>([])
 
+const { dataList: priceList } = useRequest(queryPresaleorderapplyprice, {
+    params: {
+        applyid: props.selectedRow.presaleapplyid
+    }
+})
+
 const { loading, dataList, total, pageIndex, pageSize, run } = useRequest(queryGZMyPresell, {
     params: {
         pagesize: 10,
@@ -109,6 +119,12 @@ const columns: Ermcp.TableColumn[] = [
     { prop: 'ordertime', label: '采购时间' },
 ]
 
+const priceColumns: Ermcp.TableColumn[] = [
+    { prop: 'stepindex', label: '序号' },
+    { prop: 'qty', label: '数量' },
+    { prop: 'price', label: '价格(元/克拉)' },
+]
+
 onMounted(() => {
     const images = props.selectedRow.pictureurls.split(',')
     images.forEach((url) => {

+ 2 - 2
src/packages/pc/views/centralize/partake/components/details/index.vue

@@ -1,13 +1,13 @@
 <!-- 集采交易-我参与的预售-详情 -->
 <template>
     <app-drawer title="详情" :width="960" v-model:show="show">
-        <app-table-details title="集采信息" :label-width="100" :data="selectedRow" :cell-props="details1" :column="2">
+        <app-table-details title="集采信息" :label-width="140" :data="selectedRow" :cell-props="details1" :column="2">
             <!-- 采购保证金比例 -->
             <template #marginvalue="{ value }">
                 {{ parsePercent(value) }}
             </template>
         </app-table-details>
-        <app-table-details title="钻石参考信息" :label-width="100" :data="selectedRow" :cell-props="details2" :column="2">
+        <app-table-details title="钻石参考信息" :label-width="140" :data="selectedRow" :cell-props="details2" :column="2">
             <!-- 生产方式 -->
             <template #ysproductionmode="{ value }">
                 {{ getYSProductionModeName(value) }}

+ 1 - 7
src/packages/pc/views/centralize/partake/index.vue

@@ -10,10 +10,6 @@
             <template #marginvalue="{ value }">
                 {{ parsePercent(value) }}
             </template>
-            <!-- 状态 -->
-            <template #status="{ value }">
-                {{ getWRPresaleStatusName(value) }}
-            </template>
             <!-- 操作 -->
             <template #operate="{ row }">
                 <app-auth-operation type="dropdown" :menus="['presale_partake_details']" :options="{ selectedRow: row }"
@@ -33,7 +29,6 @@ import { ElMessage } from 'element-plus'
 import { parsePercent } from '@/filters'
 import { useDataFilter } from '@/hooks/datatable'
 import { useRequest } from '@/hooks/request'
-import { getWRPresaleStatusName } from '@/constants/presale'
 import { queryGZMyTradingPreSell } from '@/services/api/presale'
 import AppTable from '@pc/components/base/table/index.vue'
 import AppPagination from '@pc/components/base/pagination/index.vue'
@@ -60,8 +55,7 @@ const tableColumns = shallowRef<Ermcp.TableColumn[]>([
     { prop: 'tradeamount', label: '货款' },
     { prop: 'marginvalue', label: '保证金比例(%)' },
     { prop: 'freezemargin', label: '已付保证金' },
-    { prop: 'status', label: '状态' },
-    { prop: 'createtime', label: '认购时间' },
+    { prop: 'ordertime', label: '认购时间' },
     { prop: 'operate', label: '操作', fixed: 'right' },
 ])
 

+ 5 - 11
src/packages/pc/views/customs/exit/components/edit/index.vue

@@ -112,7 +112,7 @@ import { ElMessage } from 'element-plus'
 import type { FormInstance, FormRules, UploadFile } from 'element-plus'
 import { read, utils } from 'xlsx'
 import { useComponent } from '@/hooks/component'
-import { validateRules } from '@/constants/regex'
+import { validate } from '@/constants/regex'
 import { enumStore } from '@/stores'
 import { getGZCJAccountTypeList, getGZCJCategoryTypeList, getGZCJDeliveryTypeList, getGZCJShapeTypeName, getGZCJPublishTypeName, getGZCJMarkTypeName, getGZCJServiceTypeName } from '@/constants/customs'
 import { useCJJCOrderApply } from '@/business/customs/exit'
@@ -207,11 +207,8 @@ const formRules: FormRules = {
         trigger: 'blur',
         validator: (rule, value, callback) => {
             if (value) {
-                if (validateRules.phone.validate(value)) {
-                    callback()
-                } else {
-                    callback(new Error(validateRules.phone.message))
-                }
+                const message = validate(value, 'phone')
+                message ? callback(new Error(message)) : callback()
             } else {
                 callback(new Error('请输入联系人电话'))
             }
@@ -222,11 +219,8 @@ const formRules: FormRules = {
         trigger: 'blur',
         validator: (rule, value, callback) => {
             if (value) {
-                if (validateRules.email.validate(value)) {
-                    callback()
-                } else {
-                    callback(new Error(validateRules.email.message))
-                }
+                const message = validate(value, 'email')
+                message ? callback(new Error(message)) : callback()
             } else {
                 callback(new Error('请输入邮箱'))
             }

+ 26 - 5
src/packages/pc/views/presale/list/components/buy/index.vue

@@ -12,10 +12,10 @@
                 {{ selectedRow.maxbuyqty }}
             </el-form-item>
             <el-form-item label="剩余预售量">
-                {{ selectedRow.presaleqty }}
+                {{ remainqty }}
             </el-form-item>
             <el-form-item label="认购数量" prop="OrderQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.OrderQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.OrderQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
@@ -28,8 +28,9 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, reactive, PropType } from 'vue'
+import { shallowRef, reactive, PropType, computed } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
+import { validate } from '@/constants/regex'
 import { gzPresaleOrder } from '@/services/api/presale'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
 import Long from 'long'
@@ -47,13 +48,33 @@ const refresh = shallowRef(false)
 const loading = shallowRef(false)
 
 const formData = reactive<Partial<Proto.GZPresaleOrderReq>>({
-    WRTradeOrderID:Long.fromString(props.selectedRow.sellwrtradeorderid), // 仓单贸易委托单ID,必填
+    WRTradeOrderID: Long.fromString(props.selectedRow.sellwrtradeorderid), // 仓单贸易委托单ID,必填
 })
 
+// 剩余预售量
+const remainqty = computed(() => props.selectedRow.presaleqty - props.selectedRow.tradeqty)
+
 const formRules: FormRules = {
     OrderQty: [{
         required: true,
-        message: '请输入认购数量'
+        validator: (rule, value, callback) => {
+            const message = validate(value, 'integer')
+            if (message) {
+                callback(new Error('请输入认购数量'))
+            } else {
+                const { minbuyqty, maxbuyqty } = props.selectedRow
+                const qty = Number(value)
+                if (qty > remainqty.value) {
+                    callback(new Error('剩余数量不足'))
+                } else if (qty < minbuyqty) {
+                    callback(new Error('数量不能小于' + minbuyqty))
+                } else if (qty > maxbuyqty) {
+                    callback(new Error('数量不能大于' + maxbuyqty))
+                } else {
+                    callback()
+                }
+            }
+        }
     }],
 }
 

+ 4 - 1
src/packages/pc/views/presale/list/components/details/index.vue

@@ -89,8 +89,11 @@ const details2 = [
     { prop: 'remark', label: '备注:', entireRow: true },
 ]
 
-const onBuyClosed = () => {
+const onBuyClosed = (isRefresh = false) => {
     showBuy.value = false
+    if (isRefresh) {
+        onCancel(true)
+    }
 }
 
 const onCancel = (isRefresh = false) => {

+ 15 - 9
src/packages/pc/views/presale/mine/components/add/index.vue

@@ -10,7 +10,7 @@
                 <component :is="PerformanceTemplate" v-model="formData.PerformanceTemplateID" />
             </el-form-item>
             <el-form-item label="预售总量" prop="PresaleQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.PresaleQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.PresaleQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
@@ -20,17 +20,17 @@
                 </el-input>
             </el-form-item>
             <el-form-item label="最小采购单位" prop="MinBuyQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.MinBuyQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.MinBuyQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
             <el-form-item label="最低成团量" prop="MinSuccessQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.MinSuccessQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.MinSuccessQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
             <el-form-item label="最大采购单位" prop="MaxBuyQty">
-                <el-input type="number" placeholder="请输入" v-model="formData.MaxBuyQty">
+                <el-input type="number" placeholder="请输入" v-model.number="formData.MaxBuyQty">
                     <template #append>(克拉)</template>
                 </el-input>
             </el-form-item>
@@ -88,6 +88,7 @@
 import { shallowRef, reactive, defineAsyncComponent } from 'vue'
 import { ElMessage, FormInstance, FormRules } from 'element-plus'
 import { formatDate } from '@/filters'
+import { regular } from '@/constants/regex'
 import { getYSProductionModeList, YSZSCategory } from '@/constants/presale'
 import { gzPresaleApply } from '@/services/api/presale'
 import AppDrawer from '@pc/components/base/drawer/index.vue'
@@ -118,7 +119,8 @@ const formRules: FormRules = {
     }],
     PresaleQty: [{
         required: true,
-        message: '请输入预售总量'
+        message: '请输入预售总量',
+        pattern: regular.integer.reg
     }],
     UnitPrice: [{
         required: true,
@@ -126,19 +128,23 @@ const formRules: FormRules = {
     }],
     MinBuyQty: [{
         required: true,
-        message: '请输入最小采购单位'
+        message: '请输入最小采购单位',
+        pattern: regular.integer.reg
     }],
     MinSuccessQty: [{
         required: true,
-        message: '请输入最低成团量'
+        message: '请输入最低成团量',
+        pattern: regular.integer.reg
     }],
     MaxBuyQty: [{
         required: true,
-        message: '请输入最大采购单位'
+        message: '请输入最大采购单位',
+        pattern: regular.integer.reg
     }],
     BuyMarginValue: [{
         required: true,
-        message: '请输入采购保证金比例'
+        message: '请输入采购保证金比例',
+        pattern: regular.positive.reg
     }],
     PreDate: [{
         required: true,

+ 2 - 2
src/packages/pc/views/presale/partake/components/details/index.vue

@@ -1,13 +1,13 @@
 <!-- 预售大厅-我参与的预售-详情 -->
 <template>
     <app-drawer title="详情" :width="960" v-model:show="show">
-        <app-table-details title="预售信息" :label-width="100" :data="selectedRow" :cell-props="details1" :column="2">
+        <app-table-details title="预售信息" :label-width="140" :data="selectedRow" :cell-props="details1" :column="2">
             <!-- 采购保证金比例 -->
             <template #marginvalue="{ value }">
                 {{ parsePercent(value) }}
             </template>
         </app-table-details>
-        <app-table-details title="钻石参考信息" :label-width="100" :data="selectedRow" :cell-props="details2" :column="2">
+        <app-table-details title="钻石参考信息" :label-width="140" :data="selectedRow" :cell-props="details2" :column="2">
             <!-- 生产方式 -->
             <template #ysproductionmode="{ value }">
                 {{ getYSProductionModeName(value) }}

+ 1 - 7
src/packages/pc/views/presale/partake/index.vue

@@ -10,10 +10,6 @@
             <template #marginvalue="{ value }">
                 {{ parsePercent(value) }}
             </template>
-            <!-- 状态 -->
-            <template #status="{ value }">
-                {{ getWRPresaleStatusName(value) }}
-            </template>
             <!-- 操作 -->
             <template #operate="{ row }">
                 <app-auth-operation type="dropdown" :menus="['presale_partake_details']" :options="{ selectedRow: row }"
@@ -33,7 +29,6 @@ import { ElMessage } from 'element-plus'
 import { parsePercent } from '@/filters'
 import { useDataFilter } from '@/hooks/datatable'
 import { useRequest } from '@/hooks/request'
-import { getWRPresaleStatusName } from '@/constants/presale'
 import { queryGZMyTradingPreSell } from '@/services/api/presale'
 import AppTable from '@pc/components/base/table/index.vue'
 import AppPagination from '@pc/components/base/pagination/index.vue'
@@ -60,8 +55,7 @@ const tableColumns = shallowRef<Ermcp.TableColumn[]>([
     { prop: 'tradeamount', label: '货款' },
     { prop: 'marginvalue', label: '保证金比例(%)' },
     { prop: 'freezemargin', label: '已付保证金' },
-    { prop: 'status', label: '状态' },
-    { prop: 'createtime', label: '认购时间' },
+    { prop: 'ordertime', label: '认购时间' },
     { prop: 'operate', label: '操作', fixed: 'right' },
 ])
 

+ 1 - 1
src/packages/pc/views/trade/buy/components/delisting/index.vue

@@ -26,7 +26,7 @@
                             汇率:{{ getExrate(selectedGoods.zscurrencytype) }}
                         </span>
                         <span style="white-space:nowrap;" v-if="formData.ApplyPrice">
-                            折合:{{ (formData.ApplyPrice * getExrate(selectedGoods.zscurrencytype)).toFixed(2) }}
+                            折合:{{ (formData.ApplyPrice * getExrate(selectedGoods.zscurrencytype)).toFixed(2) }}
                         </span>
                     </template>
                 </div>

+ 1 - 1
src/packages/pc/views/warehousing/goods/components/bargain/index.vue

@@ -9,7 +9,7 @@
                     <span>汇率:{{
                         getExrate(selectedRow.zscurrencytype) }}</span>
                     <span v-if="formData.ApplyPrice">
-                        折合:{{ (formData.ApplyPrice * getExrate(selectedRow.zscurrencytype)).toFixed(2) }}
+                        折合:{{ (formData.ApplyPrice * getExrate(selectedRow.zscurrencytype)).toFixed(2) }}
                     </span>
                 </div>
             </el-form-item>

+ 10 - 0
src/services/api/presale/index.ts

@@ -50,6 +50,16 @@ export function queryGZMyTradingPreSell(params: Ermcp.GZMyTradingPreSellReq) {
 }
 
 /**
+ * 查询预售申请价格表
+ */
+export function queryPresaleorderapplyprice(params: Ermcp.PresaleorderapplypriceReq) {
+    return http.commonRequest<Ermcp.PresaleorderapplypriceRsp[]>({
+        url: '/Guangzuan/QueryPresaleorderapplyprice',
+        params,
+    })
+}
+
+/**
  * 广钻预售申请
  */
 export function gzPresaleApply(params: Partial<Proto.GZPresaleApplyReq>) {

+ 1 - 1
src/services/socket/trade/interface.ts

@@ -8,7 +8,7 @@ export interface TradeRequestConfig<T extends object = { Header?: IMessageHead }
     params: T;
     reqName: keyof typeof FunCode;
     rspName: keyof typeof FunCode;
-    marketId?: number;
+    marketId?: null | number;
 }
 
 /**

+ 17 - 0
src/types/ermcp/presale.d.ts

@@ -49,6 +49,7 @@ declare namespace Ermcp {
         takestartdate: string; // 提货开始日期
         thumurls: string; // 缩略图片(1:1)(逗号分隔)
         tradedate: string; // 交易日
+        tradeqty: number; // 成交数量(已预售数量)
         unitid: number; // 单位ID
         unitprice: number; // 商品单价
         warehouseid: number; // 仓库ID
@@ -193,4 +194,20 @@ declare namespace Ermcp {
         zsshapetypestr: string; // 形状 [1:成品裸钻]
         zssymmetrytypestr: string; // 对称 [1:成品裸钻]
     }
+
+    /** 查询预售申请价格表 请求 */
+    interface PresaleorderapplypriceReq {
+        applyid: string; // 预售申请ID
+    }
+
+    /** 查询预售申请价格表 响应 */
+    interface PresaleorderapplypriceRsp {
+        applyid: string; // 预售申请ID
+        createtime: string; // 创建时间
+        goodscode: string; // 商品代码 系统自动生成 [#P(2位) + ApplyID十六进制(6位) ]
+        marketid: number; // 市场ID
+        price: number; // 档位价格
+        qty: number; // 档位数量
+        stepindex: number; // 档位序号
+    }
 }

+ 1 - 1
src/types/proto/presale.d.ts

@@ -126,7 +126,7 @@ declare global {
             Header?: IMessageHead;
             UserID: number; // 用户ID,必填
             AccountID: number; // 资金账户ID,必填
-            WRTradeOrderID: number; // 仓单贸易委托单ID,必填
+            WRTradeOrderID: Long; // 仓单贸易委托单ID,必填
             OrderQty: number; // 认购数量,必填
             MarketID: number; // 市场ID,必填
             ClientOrderTime: string; // 委托时间,必填