修改
This commit is contained in:
4
env/.env
vendored
4
env/.env
vendored
@@ -10,8 +10,8 @@ VITE_WX_APPID = 'wxa023ce905b13a4de'
|
|||||||
VITE_APP_PUBLIC_BASE=/
|
VITE_APP_PUBLIC_BASE=/
|
||||||
|
|
||||||
# 后台请求地址localhost
|
# 后台请求地址localhost
|
||||||
VITE_SERVER_BASEURL = 'http://1.14.158.154:48080/admin-api'
|
VITE_SERVER_BASEURL = 'https://api.tuanbanlv.com/admin-api'
|
||||||
VITE_UPLOAD_BASEURL = 'http://1.14.158.154:48080/upload'
|
VITE_UPLOAD_BASEURL = 'https://api.tuanbanlv.com/upload'
|
||||||
# 备注:如果后台带统一前缀,则也要加到后面,eg: https://ukw0y1.laf.run/api
|
# 备注:如果后台带统一前缀,则也要加到后面,eg: https://ukw0y1.laf.run/api
|
||||||
|
|
||||||
# 注意,如果是微信小程序,还有一套请求地址的配置,根据 develop、trial、release 分别设置上传地址,见 `src/utils/index.ts`。
|
# 注意,如果是微信小程序,还有一套请求地址的配置,根据 develop、trial、release 分别设置上传地址,见 `src/utils/index.ts`。
|
||||||
|
|||||||
27
private.wxa023ce905b13a4de.key
Normal file
27
private.wxa023ce905b13a4de.key
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEAqu4smP/F2ib/J2+pJp1Y379U8N18eEdNEIi0+Bw/TZSn90sN
|
||||||
|
mZvTAu/fB1kkSzjHLhvK8+TMTx/WDvD9u/9WpVlBK9rE6bx8+OcFCk5gePqDZdY0
|
||||||
|
ybd99D1oicudmO2yU+YMyBD4zM5qvdVyU5EDj6OnV1zB6D5n3pw2thICplYobN5K
|
||||||
|
osTEBr/c33RX8/3ZbRo0AdyZPcY5I3Uq6vDMCKdmJn4H0klWG3jXYtsen8HVzO3F
|
||||||
|
UWFFeiZeyBSq5iVBtm6s8w2mQhRbjc6rS0ERalrGL7mV0RjVQauL6TJrIxoI/8v4
|
||||||
|
aIOgo7gApFlqTf3nfyZw4OTEPQWrTKM2s7/qIwIDAQABAoIBAG0EoW8n2sHrk1tM
|
||||||
|
rV7ShmeWeY9yRDvWhgFgn8OLCJjrkkF4HgF10ByUbvQZ17seSHNRCJ2LtP9WN8mp
|
||||||
|
zLtF/LZS+e0FiAfnzvFVLvLG0GL4rCucdmidXnkTXYRdWHO8TruSA17q7DR8Brpy
|
||||||
|
04sW92V6pHVk1MvSWZ8ylPaFACmjyPjc/gvUdeZG1v0tUg6069r+RZegLotzhcDi
|
||||||
|
0T2N9W/0nWFIkNNCQrG5ze24NFD+FmhcNQnx/TQMUeU02JxAfA6sM6jdFcRm1j8Z
|
||||||
|
M2H/VBe1fOZjQceBHgfeexEBNWNqHB9QJIRdk51+EFC7I+CL1wIvJegrUYAQvwNm
|
||||||
|
njCzhnkCgYEA2SX45T5Zyicp8FGrYH1ufVRnipO/mwAkvlY8tbFd1C4fPB8Hkbx7
|
||||||
|
ZrM5G3293HJ2TBQO+kCIU1WyT9weVeJ7P9bruDyjNOSu1q7d4xjq49LSLXvo7C4+
|
||||||
|
T8V7z1fUZt0A0jOdaqfmw+R7ICzQAna8PI/J8elW3Vh7uNk0TRcIXZ0CgYEAyYNI
|
||||||
|
yrrpabP/sxGYfUpb+Ko6iAcISPTT7rZcN+dVGqqFb8tkvHUSPhhy/H5WYcdFFhzI
|
||||||
|
S5nMXXmRsgDDRdltukUg4zoA1um5gdI8SeOLzEdcFF0p/Pfc60G+LoY7K/aUlvy2
|
||||||
|
DeSpSHJgblZVMKw+2/lfvc2M/100BOjObWkWur8CgYEAgNthqVeonKdE4dD065tD
|
||||||
|
N6ggkUE/0FDzfOdbu033KfP8oQagzUCV0cnEt6WURv69aEP251XoD9uopm8uqTRu
|
||||||
|
guGcm4WQK9EQV2EJVrvwlyUBh/AhthVy8I91+wJZjnjTBemPHj1oWRJ6ZgtxnCSt
|
||||||
|
axrAcYdP/qWFNZneyWhDlJkCgYB+7jwuvteB5oidAetcmDcghhGCV3OniNfqGGI0
|
||||||
|
MHoR5vFQPvzAHLoV9Q6Q7v94ba2dxRmBTWpGQuo8BnD6EYAlgZ+6oXGf7e8U0Bl7
|
||||||
|
rWIElbpxdVGab4JviaTC53hkM9ja1mnSjIL5CFqnhaf5lbWumADvrIcw30OCCCbn
|
||||||
|
EffoPwKBgQDU/Q3/lZahWTr4w6NtNmyhi0EnoLv+a9afhYdii1+v5g5PfG0mDvx0
|
||||||
|
0lmX2+JNqhF5ZMlVACLY1wR0trz4Iz2LstOst1XE3ipy2zbQTF/g6ujudOxrzOuw
|
||||||
|
jr+1JcbjZfywRQO+2wgegm8Qut7cZe5AraR6cqzIZ6DUO8QtbmsJnw==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
@@ -81,3 +81,13 @@ export function generateContract(id: number) {
|
|||||||
export function generateContractHtml(id: number) {
|
export function generateContractHtml(id: number) {
|
||||||
return http.get<string>(`/car/renewal-order/generate-contract-html?id=${id}`)
|
return http.get<string>(`/car/renewal-order/generate-contract-html?id=${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 创建线上签名令牌(用于分享签名) */
|
||||||
|
export function createSignToken(id: number) {
|
||||||
|
return http.post<{ uuid: string; signUrl: string }>('/car/renewal-order/create-sign-token', undefined, { id })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 清空订单合同与客户签名(重新生成合同时先清空再扫码签名) */
|
||||||
|
export function clearContractAndSignature(id: number) {
|
||||||
|
return http.post<boolean>('/car/renewal-order/clear-contract-sign', undefined, { id })
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface RenewalProductVO {
|
|||||||
productName?: string // 产品名称
|
productName?: string // 产品名称
|
||||||
productContent?: string // 产品内容
|
productContent?: string // 产品内容
|
||||||
productType?: string // 产品类别
|
productType?: string // 产品类别
|
||||||
|
effectiveYear?: string // 生效年限(仅产品类别为无忧时有值)
|
||||||
remark?: string // 备注
|
remark?: string // 备注
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
<wd-cell title="产品类别">
|
<wd-cell title="产品类别">
|
||||||
<dict-tag :type="DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE" :value="productData?.productType" />
|
<dict-tag :type="DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE" :value="productData?.productType" />
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
|
<wd-cell v-if="showEffectiveYear" title="生效年限">
|
||||||
|
<dict-tag :type="DICT_TYPE.CAR_RENEWAL_YEAR" :value="productData?.effectiveYear" />
|
||||||
|
</wd-cell>
|
||||||
<wd-cell title="产品内容" :value="productData?.productContent || '-'" />
|
<wd-cell title="产品内容" :value="productData?.productContent || '-'" />
|
||||||
<wd-cell title="备注" :value="productData?.remark || '-'" />
|
<wd-cell title="备注" :value="productData?.remark || '-'" />
|
||||||
<wd-cell title="创建时间" :value="formatDateTime(productData?.createTime) || '-'" />
|
<wd-cell title="创建时间" :value="formatDateTime(productData?.createTime) || '-'" />
|
||||||
@@ -54,6 +57,7 @@ import { onLoad, onShow } from '@dcloudio/uni-app'
|
|||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useToast } from 'wot-design-uni'
|
import { useToast } from 'wot-design-uni'
|
||||||
import { deleteRenewalProduct, getRenewalProduct } from '@/api/car/renewalproduct'
|
import { deleteRenewalProduct, getRenewalProduct } from '@/api/car/renewalproduct'
|
||||||
|
import { getDictLabel } from '@/hooks/useDict'
|
||||||
import { useAccess } from '@/hooks/useAccess'
|
import { useAccess } from '@/hooks/useAccess'
|
||||||
import { navigateBackPlus } from '@/utils'
|
import { navigateBackPlus } from '@/utils'
|
||||||
import { DICT_TYPE } from '@/utils/constants'
|
import { DICT_TYPE } from '@/utils/constants'
|
||||||
@@ -73,6 +77,12 @@ const deleting = ref(false)
|
|||||||
const productId = ref<number>()
|
const productId = ref<number>()
|
||||||
const productData = ref<RenewalProductVO | null>(null)
|
const productData = ref<RenewalProductVO | null>(null)
|
||||||
|
|
||||||
|
/** 仅当产品类别为「无忧」或「无忧延保」时显示生效年限 */
|
||||||
|
const showEffectiveYear = computed(() => {
|
||||||
|
const label = getDictLabel(DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE, productData.value?.productType) || ''
|
||||||
|
return label === '无忧' || label === '无忧延保'
|
||||||
|
})
|
||||||
|
|
||||||
/** 返回上一页 */
|
/** 返回上一页 */
|
||||||
function handleBack() {
|
function handleBack() {
|
||||||
navigateBackPlus()
|
navigateBackPlus()
|
||||||
@@ -101,6 +111,8 @@ function handleDelete() {
|
|||||||
try {
|
try {
|
||||||
await deleteRenewalProduct(Number(productId.value))
|
await deleteRenewalProduct(Number(productId.value))
|
||||||
toast.success('删除成功')
|
toast.success('删除成功')
|
||||||
|
// 标记列表页需要刷新,返回后列表会重新拉取数据
|
||||||
|
uni.setStorageSync('renewalproduct_list_need_refresh', true)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleBack()
|
handleBack()
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|||||||
@@ -36,6 +36,17 @@
|
|||||||
label-key="label"
|
label-key="label"
|
||||||
value-key="value"
|
value-key="value"
|
||||||
/>
|
/>
|
||||||
|
<wd-picker
|
||||||
|
v-if="showEffectiveYear"
|
||||||
|
v-model="formData.effectiveYear"
|
||||||
|
:columns="effectiveYearOptions"
|
||||||
|
label="生效年限"
|
||||||
|
label-width="180rpx"
|
||||||
|
prop="effectiveYear"
|
||||||
|
placeholder="请选择生效年限"
|
||||||
|
label-key="label"
|
||||||
|
value-key="value"
|
||||||
|
/>
|
||||||
<wd-textarea
|
<wd-textarea
|
||||||
v-model="formData.productContent"
|
v-model="formData.productContent"
|
||||||
label="产品内容"
|
label="产品内容"
|
||||||
@@ -77,10 +88,10 @@
|
|||||||
import type { FormInstance } from 'wot-design-uni/components/wd-form/types'
|
import type { FormInstance } from 'wot-design-uni/components/wd-form/types'
|
||||||
import type { RenewalProductVO } from '@/api/car/renewalproduct'
|
import type { RenewalProductVO } from '@/api/car/renewalproduct'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import { useToast } from 'wot-design-uni'
|
import { useToast } from 'wot-design-uni'
|
||||||
import { createRenewalProduct, getRenewalProduct, updateRenewalProduct } from '@/api/car/renewalproduct'
|
import { createRenewalProduct, getRenewalProduct, updateRenewalProduct } from '@/api/car/renewalproduct'
|
||||||
import { getStrDictOptions } from '@/hooks/useDict'
|
import { getDictLabel, getStrDictOptions } from '@/hooks/useDict'
|
||||||
import { navigateBackPlus } from '@/utils'
|
import { navigateBackPlus } from '@/utils'
|
||||||
import { DICT_TYPE } from '@/utils/constants'
|
import { DICT_TYPE } from '@/utils/constants'
|
||||||
|
|
||||||
@@ -107,10 +118,41 @@ const productTypeOptions = computed(() => {
|
|||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 生效年限选项(仅产品类别为「无忧」时展示)
|
||||||
|
const effectiveYearOptions = computed(() => {
|
||||||
|
return getStrDictOptions(DICT_TYPE.CAR_RENEWAL_YEAR).map(item => ({
|
||||||
|
label: item.label,
|
||||||
|
value: item.value,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 仅当产品类别为「无忧」或「无忧延保」时显示生效年限 */
|
||||||
|
const showEffectiveYear = computed(() => {
|
||||||
|
const label = getDictLabel(DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE, formData.value.productType) || ''
|
||||||
|
return label === '无忧' || label === '无忧延保'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 产品类别切换为「无忧」或「无忧延保」时设置生效年限默认值,切换为其他时清空
|
||||||
|
watch(
|
||||||
|
() => formData.value.productType,
|
||||||
|
(type) => {
|
||||||
|
const label = getDictLabel(DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE, type) || ''
|
||||||
|
if (label === '无忧' || label === '无忧延保') {
|
||||||
|
const opts = getStrDictOptions(DICT_TYPE.CAR_RENEWAL_YEAR)
|
||||||
|
if (opts.length > 0 && !formData.value.effectiveYear) {
|
||||||
|
formData.value.effectiveYear = opts[0].value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formData.value.effectiveYear = undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const formData = ref<RenewalProductVO>({
|
const formData = ref<RenewalProductVO>({
|
||||||
productName: undefined,
|
productName: undefined,
|
||||||
productContent: undefined,
|
productContent: undefined,
|
||||||
productType: undefined,
|
productType: undefined,
|
||||||
|
effectiveYear: undefined,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -161,6 +203,8 @@ async function handleSubmit() {
|
|||||||
await createRenewalProduct(formData.value)
|
await createRenewalProduct(formData.value)
|
||||||
toast.success('新增成功')
|
toast.success('新增成功')
|
||||||
}
|
}
|
||||||
|
// 标记列表页需要刷新,返回后列表会重新拉取数据
|
||||||
|
uni.setStorageSync('renewalproduct_list_need_refresh', true)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigateBackPlus()
|
navigateBackPlus()
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|||||||
@@ -170,16 +170,24 @@ onReachBottom(() => {
|
|||||||
loadMore()
|
loadMore()
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 页面显示时刷新(从编辑页面返回时) */
|
/** 是否首次显示(首次不依赖 onShow 刷新,由 onMounted 拉取;从子页返回时 onShow 会再次触发并刷新) */
|
||||||
|
const isFirstShow = ref(true)
|
||||||
|
|
||||||
|
/** 页面显示时刷新(与订单列表一致:从新增/编辑/详情页返回后刷新列表) */
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
// 检查页面栈,如果上一个页面是编辑页面,则刷新
|
// 检查存储中的刷新标志(新增、编辑、删除成功后子页会设置)
|
||||||
const pages = getCurrentPages()
|
const needRefresh = uni.getStorageSync('renewalproduct_list_need_refresh')
|
||||||
if (pages.length > 1) {
|
if (needRefresh) {
|
||||||
const prevPage = pages[pages.length - 2]
|
uni.removeStorageSync('renewalproduct_list_need_refresh')
|
||||||
if (prevPage?.route?.includes('/renewalproduct/form/index')) {
|
getList(true)
|
||||||
getList(true)
|
isFirstShow.value = false
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
|
// 非首次显示时也刷新一次(从表单页或详情页返回,确保列表是最新)
|
||||||
|
if (!isFirstShow.value) {
|
||||||
|
getList(true)
|
||||||
|
}
|
||||||
|
isFirstShow.value = false
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 初始化 */
|
/** 初始化 */
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</picker>
|
</picker>
|
||||||
</view>
|
</view>
|
||||||
|
<wd-input v-model="formData.invoiceDate" prop="invoiceDate" v-show="false" />
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.invoiceAmount"
|
v-model="formData.invoiceAmount"
|
||||||
label="发票金额"
|
label="发票金额"
|
||||||
@@ -100,7 +101,7 @@
|
|||||||
clearable
|
clearable
|
||||||
placeholder="请输入购买时公里数"
|
placeholder="请输入购买时公里数"
|
||||||
/>
|
/>
|
||||||
<wd-cell title="行驶证" title-width="180rpx" />
|
<wd-cell title="行驶证" title-width="180rpx" required />
|
||||||
<view class="px-24rpx py-16rpx">
|
<view class="px-24rpx py-16rpx">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
v-model:file-list="drivingLicenseFileList"
|
v-model:file-list="drivingLicenseFileList"
|
||||||
@@ -140,7 +141,7 @@
|
|||||||
:source-type="['album', 'camera']"
|
:source-type="['album', 'camera']"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
<wd-cell title="购车发票" title-width="180rpx" />
|
<wd-cell title="购车发票" title-width="180rpx" required />
|
||||||
<view class="px-24rpx py-16rpx">
|
<view class="px-24rpx py-16rpx">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
v-model:file-list="carInvoiceFileList"
|
v-model:file-list="carInvoiceFileList"
|
||||||
@@ -150,7 +151,7 @@
|
|||||||
:source-type="['album', 'camera']"
|
:source-type="['album', 'camera']"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
<wd-cell title="购置税发票" title-width="180rpx" />
|
<wd-cell title="购置税凭证" title-width="180rpx" required />
|
||||||
<view class="px-24rpx py-16rpx">
|
<view class="px-24rpx py-16rpx">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
v-model:file-list="purchaseTaxInvoiceFileList"
|
v-model:file-list="purchaseTaxInvoiceFileList"
|
||||||
@@ -180,6 +181,7 @@
|
|||||||
v-model="formData.serviceBuyer"
|
v-model="formData.serviceBuyer"
|
||||||
label="服务购买方"
|
label="服务购买方"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="serviceBuyer"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入服务购买方"
|
placeholder="请输入服务购买方"
|
||||||
/>
|
/>
|
||||||
@@ -187,6 +189,7 @@
|
|||||||
v-model="formData.carBuyer"
|
v-model="formData.carBuyer"
|
||||||
label="车辆购买方"
|
label="车辆购买方"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="carBuyer"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入车辆购买方"
|
placeholder="请输入车辆购买方"
|
||||||
/>
|
/>
|
||||||
@@ -195,6 +198,7 @@
|
|||||||
:columns="certTypeOptions"
|
:columns="certTypeOptions"
|
||||||
label="证件类型"
|
label="证件类型"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="certType"
|
||||||
placeholder="请选择证件类型"
|
placeholder="请选择证件类型"
|
||||||
value-key="value"
|
value-key="value"
|
||||||
label-key="label"
|
label-key="label"
|
||||||
@@ -203,6 +207,7 @@
|
|||||||
v-model="formData.certNo"
|
v-model="formData.certNo"
|
||||||
label="证件号码"
|
label="证件号码"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="certNo"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入证件号码"
|
placeholder="请输入证件号码"
|
||||||
/>
|
/>
|
||||||
@@ -210,6 +215,7 @@
|
|||||||
v-model="formData.mobile"
|
v-model="formData.mobile"
|
||||||
label="联系电话"
|
label="联系电话"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="mobile"
|
||||||
type="number"
|
type="number"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入联系电话"
|
placeholder="请输入联系电话"
|
||||||
@@ -234,12 +240,12 @@
|
|||||||
:columns="storeOptions"
|
:columns="storeOptions"
|
||||||
label="门店"
|
label="门店"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="storeId"
|
||||||
placeholder="请选择门店"
|
placeholder="请选择门店"
|
||||||
value-key="id"
|
value-key="id"
|
||||||
label-key="storeName"
|
label-key="storeName"
|
||||||
disabled
|
|
||||||
/>
|
/>
|
||||||
<wd-cell title="身份证正面" title-width="180rpx" />
|
<wd-cell title="身份证正面" title-width="180rpx" required />
|
||||||
<view class="px-24rpx py-16rpx">
|
<view class="px-24rpx py-16rpx">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
v-model:file-list="idCardFrontFileList"
|
v-model:file-list="idCardFrontFileList"
|
||||||
@@ -249,7 +255,7 @@
|
|||||||
:source-type="['album', 'camera']"
|
:source-type="['album', 'camera']"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
<wd-cell title="身份证反面" title-width="180rpx" />
|
<wd-cell title="身份证反面" title-width="180rpx" required />
|
||||||
<view class="px-24rpx py-16rpx">
|
<view class="px-24rpx py-16rpx">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
v-model:file-list="idCardBackFileList"
|
v-model:file-list="idCardBackFileList"
|
||||||
@@ -280,6 +286,7 @@
|
|||||||
v-model="formData.serviceProduct"
|
v-model="formData.serviceProduct"
|
||||||
label="服务产品"
|
label="服务产品"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="serviceProduct"
|
||||||
readonly
|
readonly
|
||||||
placeholder="选择产品后自动填充"
|
placeholder="选择产品后自动填充"
|
||||||
/>
|
/>
|
||||||
@@ -287,6 +294,7 @@
|
|||||||
v-model="formData.productValidity"
|
v-model="formData.productValidity"
|
||||||
label="产品时效"
|
label="产品时效"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="productValidity"
|
||||||
readonly
|
readonly
|
||||||
placeholder="选择产品后自动填充"
|
placeholder="选择产品后自动填充"
|
||||||
/>
|
/>
|
||||||
@@ -294,6 +302,7 @@
|
|||||||
:model-value="productTypeLabel"
|
:model-value="productTypeLabel"
|
||||||
label="产品类别"
|
label="产品类别"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="productType"
|
||||||
readonly
|
readonly
|
||||||
placeholder="选择产品后自动填充"
|
placeholder="选择产品后自动填充"
|
||||||
/>
|
/>
|
||||||
@@ -301,16 +310,18 @@
|
|||||||
v-model="formData.productFee"
|
v-model="formData.productFee"
|
||||||
label="产品费用"
|
label="产品费用"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="productFee"
|
||||||
type="digit"
|
type="digit"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入产品费用"
|
placeholder="请输入产品费用"
|
||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.originalWarrantyYears"
|
v-model="formData.originalWarrantyYears"
|
||||||
label="原厂质保时长"
|
label="产品年限"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
required
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入原厂质保时长"
|
placeholder="请输入产品年限(如:3)"
|
||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.originalWarrantyMileage"
|
v-model="formData.originalWarrantyMileage"
|
||||||
@@ -325,27 +336,31 @@
|
|||||||
<!-- 选项卡4: 其他信息 -->
|
<!-- 选项卡4: 其他信息 -->
|
||||||
<view v-show="tabIndex === 3">
|
<view v-show="tabIndex === 3">
|
||||||
<wd-cell-group border title="其他信息">
|
<wd-cell-group border title="其他信息">
|
||||||
<wd-input
|
<wd-picker
|
||||||
v-model="formData.settlementMethod"
|
v-model="formData.settlementMethod"
|
||||||
|
:columns="settlementMethodOptions"
|
||||||
label="结算方式"
|
label="结算方式"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
clearable
|
prop="settlementMethod"
|
||||||
placeholder="请输入结算方式"
|
placeholder="请选择结算方式"
|
||||||
|
value-key="value"
|
||||||
|
label-key="label"
|
||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.inputUser"
|
v-model="formData.inputUser"
|
||||||
label="录单人"
|
label="录单人"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="inputUser"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入录单人"
|
placeholder="请输入录单人"
|
||||||
/>
|
/>
|
||||||
<wd-cell v-if="formData.productType === '00'" title="合同路径" title-width="180rpx">
|
<wd-cell v-if="showContractComponents" title="合同路径" title-width="180rpx">
|
||||||
<template #value>
|
<template #value>
|
||||||
<text class="text-24rpx text-[#999]">保存订单后可生成在线合同</text>
|
<text class="text-24rpx text-[#999]">保存订单后可生成在线合同</text>
|
||||||
</template>
|
</template>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-textarea
|
<wd-textarea
|
||||||
v-if="formData.productType === '00'"
|
v-if="showContractComponents"
|
||||||
v-model="formData.contractRemark"
|
v-model="formData.contractRemark"
|
||||||
label="合同备注"
|
label="合同备注"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
@@ -408,7 +423,7 @@ import type { StoreVO } from '@/api/tire/store'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useMessage, useToast } from 'wot-design-uni'
|
import { useMessage, useToast } from 'wot-design-uni'
|
||||||
import { createRenewalOrder } from '@/api/car/renewalorder'
|
import { createRenewalOrder, createSignToken } from '@/api/car/renewalorder'
|
||||||
import { findByProductType, getRenewalProduct } from '@/api/car/renewalproduct'
|
import { findByProductType, getRenewalProduct } from '@/api/car/renewalproduct'
|
||||||
import { findByProductType as findStoreByProductType } from '@/api/tire/store'
|
import { findByProductType as findStoreByProductType } from '@/api/tire/store'
|
||||||
import { getDictLabel, getStrDictOptions } from '@/hooks/useDict'
|
import { getDictLabel, getStrDictOptions } from '@/hooks/useDict'
|
||||||
@@ -428,7 +443,7 @@ const toast = useToast()
|
|||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const tokenStore = useTokenStore()
|
const tokenStore = useTokenStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const getTitle = computed(() => '新增续保订单')
|
const getTitle = computed(() => '新增订单')
|
||||||
const formLoading = ref(false)
|
const formLoading = ref(false)
|
||||||
const tabIndex = ref(0) // 当前选项卡索引
|
const tabIndex = ref(0) // 当前选项卡索引
|
||||||
const invoiceFileList = ref<UploadFile[]>([]) // 发票图片文件列表
|
const invoiceFileList = ref<UploadFile[]>([]) // 发票图片文件列表
|
||||||
@@ -447,6 +462,11 @@ const productList = ref<RenewalProductVO[]>([]) // 续保产品列表
|
|||||||
const storeOptions = computed(() => storeList.value.map(item => ({ id: item.id, storeName: item.storeName })))
|
const storeOptions = computed(() => storeList.value.map(item => ({ id: item.id, storeName: item.storeName })))
|
||||||
const productOptions = computed(() => productList.value.map(item => ({ id: item.id, productName: item.productName })))
|
const productOptions = computed(() => productList.value.map(item => ({ id: item.id, productName: item.productName })))
|
||||||
const certTypeOptions = computed(() => getStrDictOptions('car_renewal_identity_type'))
|
const certTypeOptions = computed(() => getStrDictOptions('car_renewal_identity_type'))
|
||||||
|
const settlementMethodOptions = computed(() => getStrDictOptions(DICT_TYPE.CAR_RENEWAL_PAY_METHOD))
|
||||||
|
// 判断是否显示合同相关组件(仅当产品类别为00或02时显示)
|
||||||
|
const showContractComponents = computed(() => {
|
||||||
|
return formData.value.productType === '00' || formData.value.productType === '02'
|
||||||
|
})
|
||||||
|
|
||||||
const formData = ref<RenewalOrderVO>({
|
const formData = ref<RenewalOrderVO>({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@@ -472,10 +492,10 @@ const formData = ref<RenewalOrderVO>({
|
|||||||
serviceProduct: undefined,
|
serviceProduct: undefined,
|
||||||
productType: undefined,
|
productType: undefined,
|
||||||
productValidity: undefined,
|
productValidity: undefined,
|
||||||
originalWarrantyYears: undefined,
|
originalWarrantyYears: '3',
|
||||||
originalWarrantyMileage: undefined,
|
originalWarrantyMileage: undefined,
|
||||||
productFee: undefined,
|
productFee: undefined,
|
||||||
settlementMethod: undefined,
|
settlementMethod: '00',
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
inputUser: undefined,
|
inputUser: undefined,
|
||||||
contractUrl: undefined,
|
contractUrl: undefined,
|
||||||
@@ -497,9 +517,23 @@ const formRules = {
|
|||||||
carModel: [{ required: true, message: '车型不能为空' }],
|
carModel: [{ required: true, message: '车型不能为空' }],
|
||||||
vin: [{ required: true, message: '车架号不能为空' }],
|
vin: [{ required: true, message: '车架号不能为空' }],
|
||||||
engineNo: [{ required: true, message: '发动机号不能为空' }],
|
engineNo: [{ required: true, message: '发动机号不能为空' }],
|
||||||
|
invoiceDate: [{ required: true, message: '发票日期不能为空' }],
|
||||||
invoiceAmount: [{ required: true, message: '发票金额不能为空' }],
|
invoiceAmount: [{ required: true, message: '发票金额不能为空' }],
|
||||||
purchaseMileage: [{ required: true, message: '购买时公里数不能为空' }],
|
purchaseMileage: [{ required: true, message: '购买时公里数不能为空' }],
|
||||||
|
serviceBuyer: [{ required: true, message: '服务购买方不能为空' }],
|
||||||
|
carBuyer: [{ required: true, message: '车辆购买方不能为空' }],
|
||||||
|
certType: [{ required: true, message: '证件类型不能为空' }],
|
||||||
|
certNo: [{ required: true, message: '证件号码不能为空' }],
|
||||||
|
mobile: [{ required: true, message: '联系电话不能为空' }],
|
||||||
|
storeId: [{ required: true, message: '门店不能为空' }],
|
||||||
productId: [{ required: true, message: '续保产品不能为空' }],
|
productId: [{ required: true, message: '续保产品不能为空' }],
|
||||||
|
serviceProduct: [{ required: true, message: '服务产品不能为空' }],
|
||||||
|
productType: [{ required: true, message: '产品类别不能为空' }],
|
||||||
|
productValidity: [{ required: true, message: '产品时效不能为空' }],
|
||||||
|
productFee: [{ required: true, message: '产品费用不能为空' }],
|
||||||
|
settlementMethod: [{ required: true, message: '结算方式不能为空' }],
|
||||||
|
inputUser: [{ required: true, message: '录单人不能为空' }],
|
||||||
|
originalWarrantyYears: [{ required: true, message: '产品年限不能为空' }],
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据 productType 值获取字典 label
|
// 根据 productType 值获取字典 label
|
||||||
@@ -713,7 +747,7 @@ function createUploadMethod(fieldName: keyof RenewalOrderVO): UploadMethod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 多张图片上传(购车发票、购置税发票、商业险保单) */
|
/** 多张图片上传(购车发票、购置税凭证、商业险保单) */
|
||||||
function createMultiUploadMethod(fieldName: 'carInvoiceUrls' | 'purchaseTaxInvoiceUrls' | 'businessInsurancePolicyUrls'): UploadMethod {
|
function createMultiUploadMethod(fieldName: 'carInvoiceUrls' | 'purchaseTaxInvoiceUrls' | 'businessInsurancePolicyUrls'): UploadMethod {
|
||||||
return (file, uploadFormData, options) => {
|
return (file, uploadFormData, options) => {
|
||||||
const uploadTask = uni.uploadFile({
|
const uploadTask = uni.uploadFile({
|
||||||
@@ -756,14 +790,36 @@ function createMultiUploadMethod(fieldName: 'carInvoiceUrls' | 'purchaseTaxInvoi
|
|||||||
|
|
||||||
// 订单录入页面不需要加载详情,只允许新增
|
// 订单录入页面不需要加载详情,只允许新增
|
||||||
|
|
||||||
// ========== 新增完成后合同预览逻辑(产品类别 00) ==========
|
// ========== 新增完成后合同预览逻辑(产品类别 00 或 02) ==========
|
||||||
// 流程:提交 → 创建订单 → 若 productType===00 则跳转合同预览页 → 客户签名 → 确认生成合同 → 再跳转订单详情
|
// 流程:提交 → 创建订单 → 若 productType===00 或 02 则跳转合同预览页 → 客户签名 → 确认生成合同 → 再跳转订单详情
|
||||||
// 否则:创建成功 → 提示 → 跳转订单详情
|
// 否则:创建成功 → 提示 → 跳转订单详情
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
const { valid } = await formRef.value!.validate()
|
const { valid } = await formRef.value!.validate()
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
|
|
||||||
|
// 必传文件校验:行驶证、购车发票、购置税凭证、身份证正反面
|
||||||
|
if (!formData.value.drivingLicenseUrl) {
|
||||||
|
toast.error('请上传行驶证')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.carInvoiceUrls?.length) {
|
||||||
|
toast.error('请上传购车发票')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.purchaseTaxInvoiceUrls?.length) {
|
||||||
|
toast.error('请上传购置税凭证')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.idCardFrontUrl) {
|
||||||
|
toast.error('请上传身份证正面')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.idCardBackUrl) {
|
||||||
|
toast.error('请上传身份证反面')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
const data = { ...formData.value }
|
const data = { ...formData.value }
|
||||||
@@ -777,17 +833,49 @@ async function handleSubmit() {
|
|||||||
data.invoiceDate = dayjs(data.invoiceDate).format('YYYY-MM-DD')
|
data.invoiceDate = dayjs(data.invoiceDate).format('YYYY-MM-DD')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 确保 productType 被正确传递
|
||||||
|
if (!data.productType && formData.value.productType) {
|
||||||
|
data.productType = formData.value.productType
|
||||||
|
}
|
||||||
const raw = await createRenewalOrder(data) as unknown
|
const raw = await createRenewalOrder(data) as unknown
|
||||||
const id = (raw as { data?: number })?.data ?? (raw as number)
|
const id = (raw as { data?: number })?.data ?? (raw as number)
|
||||||
const isProduct00 = formData.value.productType === '00'
|
// 检查产品类别是否为 00 或 02
|
||||||
|
const productType = data.productType || formData.value.productType
|
||||||
|
const needContract = (productType === '00' || productType === '02') && id
|
||||||
|
|
||||||
if (isProduct00 && id) {
|
console.log('新增订单提交 - productType:', productType, 'needContract:', needContract, 'id:', id, 'data:', data)
|
||||||
// 新增完成 → 跳转合同预览 → 客户签名 → 确认生成合同 → 合同预览页内再跳转详情
|
|
||||||
|
if (needContract) {
|
||||||
|
// 新增完成 → 弹出选项:直接签名 / 分享签名
|
||||||
uni.setStorageSync('renewalorder_list_need_refresh', true)
|
uni.setStorageSync('renewalorder_list_need_refresh', true)
|
||||||
uni.navigateTo({
|
toast.show('订单已创建,请选择签名方式')
|
||||||
url: `/pages/car/renewalorder/contract-preview/index?id=${id}&from=add`,
|
uni.showActionSheet({
|
||||||
|
itemList: ['直接签名', '分享签名'],
|
||||||
|
success: async (res) => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/contract-preview/index?id=${id}&from=add`,
|
||||||
|
})
|
||||||
|
toast.show('请完成客户签名后生成合同')
|
||||||
|
} else if (res.tapIndex === 1) {
|
||||||
|
try {
|
||||||
|
const tokenRes = await createSignToken(id) as { data?: { signUrl?: string }; signUrl?: string }
|
||||||
|
const signUrl = tokenRes?.data?.signUrl ?? tokenRes?.signUrl
|
||||||
|
if (!signUrl) {
|
||||||
|
toast.show('生成签名链接失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/sign-share/index?signUrl=${encodeURIComponent(signUrl)}`,
|
||||||
|
})
|
||||||
|
toast.show('请分享链接给客户签名,签名成功后合同将自动生成')
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
toast.error('操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
toast.show('订单已创建,请完成客户签名后生成合同')
|
|
||||||
} else {
|
} else {
|
||||||
// 非 00 产品:直接提示成功并跳转详情
|
// 非 00 产品:直接提示成功并跳转详情
|
||||||
toast.success('新增成功')
|
toast.success('新增成功')
|
||||||
@@ -806,14 +894,24 @@ async function handleSubmit() {
|
|||||||
/** 初始化 */
|
/** 初始化 */
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await Promise.all([getStoreList(), getProductList()])
|
await Promise.all([getStoreList(), getProductList()])
|
||||||
// 新增:默认选择门店第一项
|
// 新增:默认选择当前用户所在门店;车辆购买方默认为当前用户门店名称,均可修改
|
||||||
if (!formData.value.storeId && storeList.value.length > 0) {
|
if (userStore.storeId != null && storeList.value.some(s => s.id === userStore.storeId)) {
|
||||||
formData.value.storeId = storeList.value[0].id
|
formData.value.storeId = userStore.storeId
|
||||||
|
formData.value.serviceBuyer = userStore.storeName || storeList.value.find(s => s.id === userStore.storeId)?.storeName || ''
|
||||||
|
} else if (storeList.value.length > 0) {
|
||||||
|
if (!formData.value.storeId) formData.value.storeId = storeList.value[0].id
|
||||||
|
if (!formData.value.serviceBuyer) formData.value.serviceBuyer = userStore.storeName || storeList.value[0].storeName || ''
|
||||||
}
|
}
|
||||||
// 新增:默认选择证件类型字典第一项
|
// 新增:默认选择证件类型字典第一项
|
||||||
if (!formData.value.certType && certTypeOptions.value.length > 0) {
|
if (!formData.value.certType && certTypeOptions.value.length > 0) {
|
||||||
formData.value.certType = certTypeOptions.value[0].value
|
formData.value.certType = certTypeOptions.value[0].value
|
||||||
}
|
}
|
||||||
|
// 新增:默认选择结算方式为 '00'
|
||||||
|
if (!formData.value.settlementMethod) {
|
||||||
|
formData.value.settlementMethod = '00'
|
||||||
|
}
|
||||||
|
// 新增:录单人默认当前登录用户名称,可修改
|
||||||
|
formData.value.inputUser = userStore.userInfo?.nickname || userStore.userInfo?.username || ''
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ async function load() {
|
|||||||
previewLoading.value = true
|
previewLoading.value = true
|
||||||
try {
|
try {
|
||||||
await Promise.all([fetchOrder(), fetchHtml()])
|
await Promise.all([fetchOrder(), fetchHtml()])
|
||||||
|
// 如果是新增订单后跳转过来的,提示用户可以签名
|
||||||
|
if (fromAdd.value === 'add' || fromAdd.value === 'form_create') {
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.show('请预览合同内容,确认无误后点击"点击签名"按钮进行签名')
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('加载合同预览失败', e)
|
console.error('加载合同预览失败', e)
|
||||||
toast.error('加载失败')
|
toast.error('加载失败')
|
||||||
@@ -172,9 +178,13 @@ onLoad((options) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/** 从签名页返回时刷新订单,以更新“已签名”状态 */
|
/** 从签名页返回时刷新订单,以更新“已签名”状态 */
|
||||||
onShow(() => {
|
onShow(async () => {
|
||||||
if (orderId.value && !previewLoading.value) {
|
if (orderId.value && !previewLoading.value) {
|
||||||
fetchOrder()
|
await fetchOrder()
|
||||||
|
// 如果是新增订单后跳转过来的(add 或 form_create),签名完成后自动提示可以生成合同
|
||||||
|
if ((fromAdd.value === 'add' || fromAdd.value === 'form_create') && order.value?.customerSignatureUrl) {
|
||||||
|
toast.show('签名已完成,请点击"确认生成合同"按钮生成合同')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -153,7 +153,7 @@
|
|||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-cell title="购置税发票" title-width="180rpx">
|
<wd-cell title="购置税凭证" title-width="180rpx">
|
||||||
<view class="flex items-center justify-end">
|
<view class="flex items-center justify-end">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
v-model:file-list="purchaseTaxInvoiceFileList"
|
v-model:file-list="purchaseTaxInvoiceFileList"
|
||||||
@@ -326,11 +326,10 @@
|
|||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.originalWarrantyYears"
|
v-model="formData.originalWarrantyYears"
|
||||||
label="原厂质保时长"
|
label="产品年限"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
clearable
|
|
||||||
placeholder="请输入原厂质保时长"
|
|
||||||
readonly
|
readonly
|
||||||
|
placeholder="-"
|
||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.originalWarrantyMileage"
|
v-model="formData.originalWarrantyMileage"
|
||||||
@@ -362,7 +361,7 @@
|
|||||||
placeholder="请输入录单人"
|
placeholder="请输入录单人"
|
||||||
readonly
|
readonly
|
||||||
/>
|
/>
|
||||||
<wd-cell v-if="formData.productType === '00'" title="合同路径" title-width="180rpx">
|
<wd-cell v-if="formData.productType === '00' || formData.productType === '02'" title="合同路径" title-width="180rpx">
|
||||||
<view class="contract-area">
|
<view class="contract-area">
|
||||||
<view class="contract-row contract-row-top">
|
<view class="contract-row contract-row-top">
|
||||||
<view
|
<view
|
||||||
@@ -388,7 +387,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-textarea
|
<wd-textarea
|
||||||
v-if="formData.productType === '00'"
|
v-if="formData.productType === '00' || formData.productType === '02'"
|
||||||
v-model="formData.contractRemark"
|
v-model="formData.contractRemark"
|
||||||
label="合同备注"
|
label="合同备注"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
@@ -424,7 +423,7 @@ import dayjs from 'dayjs'
|
|||||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useToast } from 'wot-design-uni'
|
import { useToast } from 'wot-design-uni'
|
||||||
import { getRenewalOrder } from '@/api/car/renewalorder'
|
import { clearContractAndSignature, createSignToken, getRenewalOrder } from '@/api/car/renewalorder'
|
||||||
import { findByProductType, getRenewalProduct } from '@/api/car/renewalproduct'
|
import { findByProductType, getRenewalProduct } from '@/api/car/renewalproduct'
|
||||||
import { findByProductType as findStoreByProductType } from '@/api/tire/store'
|
import { findByProductType as findStoreByProductType } from '@/api/tire/store'
|
||||||
import { getEnvBaseUrl, navigateBackPlus } from '@/utils'
|
import { getEnvBaseUrl, navigateBackPlus } from '@/utils'
|
||||||
@@ -454,7 +453,7 @@ const certificateOfConformityFileList = ref<UploadFile[]>([]) // 合格证文件
|
|||||||
const odometerPhotoFileList = ref<UploadFile[]>([]) // 里程表照片文件列表
|
const odometerPhotoFileList = ref<UploadFile[]>([]) // 里程表照片文件列表
|
||||||
const nameplatePhotoFileList = ref<UploadFile[]>([]) // 车名牌照片文件列表
|
const nameplatePhotoFileList = ref<UploadFile[]>([]) // 车名牌照片文件列表
|
||||||
const carInvoiceFileList = ref<UploadFile[]>([]) // 购车发票文件列表
|
const carInvoiceFileList = ref<UploadFile[]>([]) // 购车发票文件列表
|
||||||
const purchaseTaxInvoiceFileList = ref<UploadFile[]>([]) // 购置税发票文件列表
|
const purchaseTaxInvoiceFileList = ref<UploadFile[]>([]) // 购置税凭证文件列表
|
||||||
const businessInsurancePolicyFileList = ref<UploadFile[]>([]) // 商业险保单文件列表
|
const businessInsurancePolicyFileList = ref<UploadFile[]>([]) // 商业险保单文件列表
|
||||||
|
|
||||||
const storeOptions = computed(() => storeList.value.map(item => ({ id: item.id, storeName: item.storeName })))
|
const storeOptions = computed(() => storeList.value.map(item => ({ id: item.id, storeName: item.storeName })))
|
||||||
@@ -488,7 +487,7 @@ const formData = ref<RenewalOrderVO>({
|
|||||||
productId: undefined,
|
productId: undefined,
|
||||||
serviceProduct: undefined,
|
serviceProduct: undefined,
|
||||||
productValidity: undefined,
|
productValidity: undefined,
|
||||||
originalWarrantyYears: undefined,
|
originalWarrantyYears: '3',
|
||||||
originalWarrantyMileage: undefined,
|
originalWarrantyMileage: undefined,
|
||||||
productFee: undefined,
|
productFee: undefined,
|
||||||
settlementMethod: undefined,
|
settlementMethod: undefined,
|
||||||
@@ -718,21 +717,57 @@ async function getDetail() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 预览并生成合同:跳转合同预览页,签名后可确认生成 */
|
/** 生成/重新生成合同:弹出选项(直接签名 / 分享签名) */
|
||||||
function handlePreviewContract() {
|
function handlePreviewContract() {
|
||||||
if (!orderId.value) {
|
if (!orderId.value) {
|
||||||
toast.show('订单编号为空')
|
toast.show('订单编号为空')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (formData.value.productType !== '00') {
|
if (formData.value.productType !== '00' && formData.value.productType !== '02') {
|
||||||
toast.show('当前产品类别不支持生成合同')
|
toast.show('当前产品类别不支持生成合同,仅产品类别为 00 或 02 时可生成合同')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.showActionSheet({
|
||||||
url: `/pages/car/renewalorder/contract-preview/index?id=${orderId.value}`,
|
itemList: ['直接签名', '分享签名'],
|
||||||
|
success: (res) => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
// 直接签名:跳转合同预览页
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/contract-preview/index?id=${orderId.value}`,
|
||||||
|
})
|
||||||
|
} else if (res.tapIndex === 1) {
|
||||||
|
// 分享签名:创建令牌后跳转分享页
|
||||||
|
doOpenShareSign(Number(orderId.value))
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 分享签名:若有合同则先清空,再创建令牌并跳转分享页 */
|
||||||
|
async function doOpenShareSign(id: number) {
|
||||||
|
try {
|
||||||
|
const hadContract = !!formData.value.contractUrl
|
||||||
|
if (hadContract) {
|
||||||
|
await clearContractAndSignature(id)
|
||||||
|
formData.value.contractUrl = undefined
|
||||||
|
formData.value.customerSignatureUrl = undefined
|
||||||
|
toast.show('已清空合同与签名,请分享链接给客户签名')
|
||||||
|
}
|
||||||
|
const res = await createSignToken(id) as { data?: { signUrl?: string }; signUrl?: string }
|
||||||
|
const signUrl = res?.data?.signUrl ?? res?.signUrl
|
||||||
|
if (!signUrl) {
|
||||||
|
toast.show('生成签名链接失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/sign-share/index?signUrl=${encodeURIComponent(signUrl)}`,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
toast.error('操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 页面加载时获取路由参数 */
|
/** 页面加载时获取路由参数 */
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
if (options?.id) {
|
if (options?.id) {
|
||||||
|
|||||||
@@ -69,13 +69,20 @@
|
|||||||
clearable
|
clearable
|
||||||
placeholder="请输入发动机号"
|
placeholder="请输入发动机号"
|
||||||
/>
|
/>
|
||||||
<wd-datetime-picker
|
<wd-cell title="发票日期" title-width="180rpx">
|
||||||
v-model="formData.invoiceDate"
|
<template #value>
|
||||||
label="发票日期"
|
<picker
|
||||||
label-width="180rpx"
|
mode="date"
|
||||||
type="date"
|
:value="formData.invoiceDate || getDefaultDate()"
|
||||||
placeholder="请选择发票日期"
|
@change="onInvoiceDateChange"
|
||||||
/>
|
>
|
||||||
|
<view class="invoice-date-picker-value">
|
||||||
|
{{ formData.invoiceDate || getDefaultDate() || '请选择发票日期' }}
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</template>
|
||||||
|
</wd-cell>
|
||||||
|
<wd-input v-model="formData.invoiceDate" prop="invoiceDate" v-show="false" />
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.invoiceAmount"
|
v-model="formData.invoiceAmount"
|
||||||
label="发票金额"
|
label="发票金额"
|
||||||
@@ -94,7 +101,7 @@
|
|||||||
clearable
|
clearable
|
||||||
placeholder="请输入购买时公里数"
|
placeholder="请输入购买时公里数"
|
||||||
/>
|
/>
|
||||||
<wd-cell title="行驶证" title-width="180rpx">
|
<wd-cell title="行驶证" title-width="180rpx" required>
|
||||||
<template #value>
|
<template #value>
|
||||||
<view class="flex items-center justify-end">
|
<view class="flex items-center justify-end">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
@@ -146,7 +153,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-cell title="购车发票" title-width="180rpx">
|
<wd-cell title="购车发票" title-width="180rpx" required>
|
||||||
<template #value>
|
<template #value>
|
||||||
<view class="flex items-center justify-end">
|
<view class="flex items-center justify-end">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
@@ -159,7 +166,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-cell title="购置税发票" title-width="180rpx">
|
<wd-cell title="购置税凭证" title-width="180rpx" required>
|
||||||
<template #value>
|
<template #value>
|
||||||
<view class="flex items-center justify-end">
|
<view class="flex items-center justify-end">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
@@ -195,6 +202,7 @@
|
|||||||
v-model="formData.serviceBuyer"
|
v-model="formData.serviceBuyer"
|
||||||
label="服务购买方"
|
label="服务购买方"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="serviceBuyer"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入服务购买方"
|
placeholder="请输入服务购买方"
|
||||||
/>
|
/>
|
||||||
@@ -202,6 +210,7 @@
|
|||||||
v-model="formData.carBuyer"
|
v-model="formData.carBuyer"
|
||||||
label="车辆购买方"
|
label="车辆购买方"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="carBuyer"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入车辆购买方"
|
placeholder="请输入车辆购买方"
|
||||||
/>
|
/>
|
||||||
@@ -210,6 +219,7 @@
|
|||||||
:columns="certTypeOptions"
|
:columns="certTypeOptions"
|
||||||
label="证件类型"
|
label="证件类型"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="certType"
|
||||||
placeholder="请选择证件类型"
|
placeholder="请选择证件类型"
|
||||||
value-key="value"
|
value-key="value"
|
||||||
label-key="label"
|
label-key="label"
|
||||||
@@ -218,6 +228,7 @@
|
|||||||
v-model="formData.certNo"
|
v-model="formData.certNo"
|
||||||
label="证件号码"
|
label="证件号码"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="certNo"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入证件号码"
|
placeholder="请输入证件号码"
|
||||||
/>
|
/>
|
||||||
@@ -225,6 +236,7 @@
|
|||||||
v-model="formData.mobile"
|
v-model="formData.mobile"
|
||||||
label="联系电话"
|
label="联系电话"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="mobile"
|
||||||
type="number"
|
type="number"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入联系电话"
|
placeholder="请输入联系电话"
|
||||||
@@ -249,6 +261,7 @@
|
|||||||
:columns="storeOptions"
|
:columns="storeOptions"
|
||||||
label="门店"
|
label="门店"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="storeId"
|
||||||
placeholder="请选择门店"
|
placeholder="请选择门店"
|
||||||
value-key="id"
|
value-key="id"
|
||||||
label-key="storeName"
|
label-key="storeName"
|
||||||
@@ -266,7 +279,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-cell title="身份证正面" title-width="180rpx">
|
<wd-cell title="身份证正面" title-width="180rpx" required>
|
||||||
<template #value>
|
<template #value>
|
||||||
<view class="flex items-center justify-end">
|
<view class="flex items-center justify-end">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
@@ -279,7 +292,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-cell title="身份证反面" title-width="180rpx">
|
<wd-cell title="身份证反面" title-width="180rpx" required>
|
||||||
<template #value>
|
<template #value>
|
||||||
<view class="flex items-center justify-end">
|
<view class="flex items-center justify-end">
|
||||||
<wd-upload
|
<wd-upload
|
||||||
@@ -313,6 +326,7 @@
|
|||||||
v-model="formData.serviceProduct"
|
v-model="formData.serviceProduct"
|
||||||
label="服务产品"
|
label="服务产品"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="serviceProduct"
|
||||||
readonly
|
readonly
|
||||||
placeholder="选择产品后自动填充"
|
placeholder="选择产品后自动填充"
|
||||||
/>
|
/>
|
||||||
@@ -320,6 +334,7 @@
|
|||||||
v-model="formData.productValidity"
|
v-model="formData.productValidity"
|
||||||
label="产品时效"
|
label="产品时效"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="productValidity"
|
||||||
readonly
|
readonly
|
||||||
placeholder="选择产品后自动填充"
|
placeholder="选择产品后自动填充"
|
||||||
/>
|
/>
|
||||||
@@ -327,6 +342,7 @@
|
|||||||
:model-value="productTypeLabel"
|
:model-value="productTypeLabel"
|
||||||
label="产品类别"
|
label="产品类别"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="productType"
|
||||||
readonly
|
readonly
|
||||||
placeholder="选择产品后自动填充"
|
placeholder="选择产品后自动填充"
|
||||||
/>
|
/>
|
||||||
@@ -334,16 +350,18 @@
|
|||||||
v-model="formData.productFee"
|
v-model="formData.productFee"
|
||||||
label="产品费用"
|
label="产品费用"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="productFee"
|
||||||
type="digit"
|
type="digit"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入产品费用"
|
placeholder="请输入产品费用"
|
||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.originalWarrantyYears"
|
v-model="formData.originalWarrantyYears"
|
||||||
label="原厂质保时长"
|
label="产品年限"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
required
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入原厂质保时长"
|
placeholder="请输入产品年限(如:3)"
|
||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.originalWarrantyMileage"
|
v-model="formData.originalWarrantyMileage"
|
||||||
@@ -358,21 +376,25 @@
|
|||||||
<!-- 选项卡4: 其他信息 -->
|
<!-- 选项卡4: 其他信息 -->
|
||||||
<view v-show="tabIndex === 3">
|
<view v-show="tabIndex === 3">
|
||||||
<wd-cell-group border title="其他信息">
|
<wd-cell-group border title="其他信息">
|
||||||
<wd-input
|
<wd-picker
|
||||||
v-model="formData.settlementMethod"
|
v-model="formData.settlementMethod"
|
||||||
|
:columns="settlementMethodOptions"
|
||||||
label="结算方式"
|
label="结算方式"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
clearable
|
prop="settlementMethod"
|
||||||
placeholder="请输入结算方式"
|
placeholder="请选择结算方式"
|
||||||
|
value-key="value"
|
||||||
|
label-key="label"
|
||||||
/>
|
/>
|
||||||
<wd-input
|
<wd-input
|
||||||
v-model="formData.inputUser"
|
v-model="formData.inputUser"
|
||||||
label="录单人"
|
label="录单人"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
|
prop="inputUser"
|
||||||
clearable
|
clearable
|
||||||
placeholder="请输入录单人"
|
placeholder="请输入录单人"
|
||||||
/>
|
/>
|
||||||
<wd-cell v-if="formData.productType === '00'" title="合同路径" title-width="180rpx">
|
<wd-cell v-if="showContractComponents" title="合同路径" title-width="180rpx">
|
||||||
<template #value>
|
<template #value>
|
||||||
<view class="contract-area">
|
<view class="contract-area">
|
||||||
<view class="contract-row contract-row-top">
|
<view class="contract-row contract-row-top">
|
||||||
@@ -397,7 +419,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</wd-cell>
|
</wd-cell>
|
||||||
<wd-textarea
|
<wd-textarea
|
||||||
v-if="formData.productType === '00'"
|
v-if="showContractComponents"
|
||||||
v-model="formData.contractRemark"
|
v-model="formData.contractRemark"
|
||||||
label="合同备注"
|
label="合同备注"
|
||||||
label-width="180rpx"
|
label-width="180rpx"
|
||||||
@@ -457,11 +479,18 @@ import type { RenewalProductVO } from '@/api/car/renewalproduct'
|
|||||||
import type { StoreVO } from '@/api/tire/store'
|
import type { StoreVO } from '@/api/tire/store'
|
||||||
import type { UploadFile, UploadMethod } from 'wot-design-uni/components/wd-upload/types'
|
import type { UploadFile, UploadMethod } from 'wot-design-uni/components/wd-upload/types'
|
||||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref, watch, nextTick } from 'vue'
|
||||||
import { useToast, useMessage } from 'wot-design-uni'
|
import { useToast, useMessage } from 'wot-design-uni'
|
||||||
import { createRenewalOrder, getRenewalOrder, updateRenewalOrder } from '@/api/car/renewalorder'
|
import {
|
||||||
|
clearContractAndSignature,
|
||||||
|
createRenewalOrder,
|
||||||
|
createSignToken,
|
||||||
|
getRenewalOrder,
|
||||||
|
updateRenewalOrder,
|
||||||
|
} from '@/api/car/renewalorder'
|
||||||
import { findByProductType, getRenewalProduct } from '@/api/car/renewalproduct'
|
import { findByProductType, getRenewalProduct } from '@/api/car/renewalproduct'
|
||||||
import { findByProductType as findStoreByProductType } from '@/api/tire/store'
|
import { findByProductType as findStoreByProductType } from '@/api/tire/store'
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
import { getEnvBaseUrl, navigateBackPlus } from '@/utils'
|
import { getEnvBaseUrl, navigateBackPlus } from '@/utils'
|
||||||
import { getDictLabel, getStrDictOptions } from '@/hooks/useDict'
|
import { getDictLabel, getStrDictOptions } from '@/hooks/useDict'
|
||||||
import { DICT_TYPE } from '@/utils/constants'
|
import { DICT_TYPE } from '@/utils/constants'
|
||||||
@@ -482,7 +511,8 @@ definePage({
|
|||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const getTitle = computed(() => props.id ? '编辑续保订单' : '新增续保订单')
|
const userStore = useUserStore()
|
||||||
|
const getTitle = computed(() => props.id ? '编辑订单' : '新增订单')
|
||||||
const formLoading = ref(false)
|
const formLoading = ref(false)
|
||||||
const tabIndex = ref(0) // 当前选项卡索引
|
const tabIndex = ref(0) // 当前选项卡索引
|
||||||
const storeList = ref<StoreVO[]>([]) // 门店列表
|
const storeList = ref<StoreVO[]>([]) // 门店列表
|
||||||
@@ -496,17 +526,23 @@ const certificateOfConformityFileList = ref<UploadFile[]>([]) // 合格证文件
|
|||||||
const odometerPhotoFileList = ref<UploadFile[]>([]) // 里程表照片文件列表
|
const odometerPhotoFileList = ref<UploadFile[]>([]) // 里程表照片文件列表
|
||||||
const nameplatePhotoFileList = ref<UploadFile[]>([]) // 车名牌照片文件列表
|
const nameplatePhotoFileList = ref<UploadFile[]>([]) // 车名牌照片文件列表
|
||||||
const carInvoiceFileList = ref<UploadFile[]>([]) // 购车发票文件列表
|
const carInvoiceFileList = ref<UploadFile[]>([]) // 购车发票文件列表
|
||||||
const purchaseTaxInvoiceFileList = ref<UploadFile[]>([]) // 购置税发票文件列表
|
const purchaseTaxInvoiceFileList = ref<UploadFile[]>([]) // 购置税凭证文件列表
|
||||||
const businessInsurancePolicyFileList = ref<UploadFile[]>([]) // 商业险保单文件列表
|
const businessInsurancePolicyFileList = ref<UploadFile[]>([]) // 商业险保单文件列表
|
||||||
|
|
||||||
const storeOptions = computed(() => storeList.value.map(item => ({ id: item.id, storeName: item.storeName })))
|
const storeOptions = computed(() => storeList.value.map(item => ({ id: item.id, storeName: item.storeName })))
|
||||||
const productOptions = computed(() => productList.value.map(item => ({ id: item.id, productName: item.productName })))
|
const productOptions = computed(() => productList.value.map(item => ({ id: item.id, productName: item.productName })))
|
||||||
const certTypeOptions = computed(() => getStrDictOptions('car_renewal_identity_type'))
|
const certTypeOptions = computed(() => getStrDictOptions('car_renewal_identity_type'))
|
||||||
|
const settlementMethodOptions = computed(() => getStrDictOptions(DICT_TYPE.CAR_RENEWAL_PAY_METHOD))
|
||||||
// 根据 productType 值获取字典 label
|
// 根据 productType 值获取字典 label
|
||||||
const productTypeLabel = computed(() => {
|
const productTypeLabel = computed(() => {
|
||||||
if (!formData.value.productType) return ''
|
if (!formData.value.productType) return ''
|
||||||
return getDictLabel(DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE, formData.value.productType) || formData.value.productType
|
return getDictLabel(DICT_TYPE.CAR_RENEWAL_PRODUCT_TYPE, formData.value.productType) || formData.value.productType
|
||||||
})
|
})
|
||||||
|
// 判断是否显示合同相关组件(仅当产品类别为00或02时显示)
|
||||||
|
const showContractComponents = computed(() => {
|
||||||
|
return formData.value.productType === '00' || formData.value.productType === '02'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
const formData = ref<RenewalOrderVO>({
|
const formData = ref<RenewalOrderVO>({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@@ -518,7 +554,14 @@ const formData = ref<RenewalOrderVO>({
|
|||||||
purchaseMileage: undefined,
|
purchaseMileage: undefined,
|
||||||
engineNo: undefined,
|
engineNo: undefined,
|
||||||
vin: undefined,
|
vin: undefined,
|
||||||
invoiceDate: undefined,
|
invoiceDate: (() => {
|
||||||
|
// 设置默认值为当前日期,避免 wd-datetime-picker 收到 undefined 报错
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
})(),
|
||||||
invoiceUrl: undefined,
|
invoiceUrl: undefined,
|
||||||
serviceBuyer: undefined,
|
serviceBuyer: undefined,
|
||||||
carBuyer: undefined,
|
carBuyer: undefined,
|
||||||
@@ -532,10 +575,10 @@ const formData = ref<RenewalOrderVO>({
|
|||||||
serviceProduct: undefined,
|
serviceProduct: undefined,
|
||||||
productType: undefined,
|
productType: undefined,
|
||||||
productValidity: undefined,
|
productValidity: undefined,
|
||||||
originalWarrantyYears: undefined,
|
originalWarrantyYears: '3',
|
||||||
originalWarrantyMileage: undefined,
|
originalWarrantyMileage: undefined,
|
||||||
productFee: undefined,
|
productFee: undefined,
|
||||||
settlementMethod: undefined,
|
settlementMethod: '00',
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
inputUser: undefined,
|
inputUser: undefined,
|
||||||
contractRemark: undefined,
|
contractRemark: undefined,
|
||||||
@@ -558,9 +601,23 @@ const formRules = {
|
|||||||
carModel: [{ required: true, message: '车型不能为空' }],
|
carModel: [{ required: true, message: '车型不能为空' }],
|
||||||
vin: [{ required: true, message: '车架号不能为空' }],
|
vin: [{ required: true, message: '车架号不能为空' }],
|
||||||
engineNo: [{ required: true, message: '发动机号不能为空' }],
|
engineNo: [{ required: true, message: '发动机号不能为空' }],
|
||||||
|
invoiceDate: [{ required: true, message: '发票日期不能为空' }],
|
||||||
invoiceAmount: [{ required: true, message: '发票金额不能为空' }],
|
invoiceAmount: [{ required: true, message: '发票金额不能为空' }],
|
||||||
purchaseMileage: [{ required: true, message: '购买时公里数不能为空' }],
|
purchaseMileage: [{ required: true, message: '购买时公里数不能为空' }],
|
||||||
|
serviceBuyer: [{ required: true, message: '服务购买方不能为空' }],
|
||||||
|
carBuyer: [{ required: true, message: '车辆购买方不能为空' }],
|
||||||
|
certType: [{ required: true, message: '证件类型不能为空' }],
|
||||||
|
certNo: [{ required: true, message: '证件号码不能为空' }],
|
||||||
|
mobile: [{ required: true, message: '联系电话不能为空' }],
|
||||||
|
storeId: [{ required: true, message: '门店不能为空' }],
|
||||||
productId: [{ required: true, message: '续保产品不能为空' }],
|
productId: [{ required: true, message: '续保产品不能为空' }],
|
||||||
|
serviceProduct: [{ required: true, message: '服务产品不能为空' }],
|
||||||
|
productType: [{ required: true, message: '产品类别不能为空' }],
|
||||||
|
productValidity: [{ required: true, message: '产品时效不能为空' }],
|
||||||
|
productFee: [{ required: true, message: '产品费用不能为空' }],
|
||||||
|
settlementMethod: [{ required: true, message: '结算方式不能为空' }],
|
||||||
|
inputUser: [{ required: true, message: '录单人不能为空' }],
|
||||||
|
originalWarrantyYears: [{ required: true, message: '产品年限不能为空' }],
|
||||||
}
|
}
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
@@ -595,13 +652,16 @@ async function handleNextTab() {
|
|||||||
let validFields: string[] = []
|
let validFields: string[] = []
|
||||||
if (tabIndex.value === 0) {
|
if (tabIndex.value === 0) {
|
||||||
// 验证车辆信息
|
// 验证车辆信息
|
||||||
validFields = ['licensePlate', 'carBrand', 'carModel', 'vin', 'engineNo', 'invoiceAmount', 'purchaseMileage']
|
validFields = ['licensePlate', 'carBrand', 'carModel', 'vin', 'engineNo', 'invoiceDate', 'invoiceAmount', 'purchaseMileage']
|
||||||
} else if (tabIndex.value === 1) {
|
} else if (tabIndex.value === 1) {
|
||||||
// 购买方信息无必填项
|
// 验证购买方信息
|
||||||
validFields = []
|
validFields = ['serviceBuyer', 'carBuyer', 'certType', 'certNo', 'mobile', 'storeId']
|
||||||
} else if (tabIndex.value === 2) {
|
} else if (tabIndex.value === 2) {
|
||||||
// 验证产品信息
|
// 验证产品信息
|
||||||
validFields = ['productId']
|
validFields = ['productId', 'serviceProduct', 'productType', 'productValidity', 'productFee', 'originalWarrantyYears']
|
||||||
|
} else if (tabIndex.value === 3) {
|
||||||
|
// 验证其他信息
|
||||||
|
validFields = ['settlementMethod', 'inputUser']
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validFields.length > 0) {
|
if (validFields.length > 0) {
|
||||||
@@ -636,6 +696,25 @@ async function getProductList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 获取默认日期 */
|
||||||
|
function getDefaultDate() {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 发票日期选择(原生 picker,避免 wd-datetime-picker Invalid array length 错误) */
|
||||||
|
function onInvoiceDateChange(e: { detail: { value: string } }) {
|
||||||
|
const v = e.detail?.value
|
||||||
|
if (v && /^\d{4}-\d{2}-\d{2}$/.test(v)) {
|
||||||
|
formData.value.invoiceDate = v
|
||||||
|
} else {
|
||||||
|
formData.value.invoiceDate = getDefaultDate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 处理产品选择变化 */
|
/** 处理产品选择变化 */
|
||||||
async function handleProductChange({ value }: { value: number }) {
|
async function handleProductChange({ value }: { value: number }) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
@@ -751,22 +830,56 @@ const contractFileName = computed(() => {
|
|||||||
return formData.value.contractUrl ? getFileNameFromUrl(formData.value.contractUrl) : '合同.pdf'
|
return formData.value.contractUrl ? getFileNameFromUrl(formData.value.contractUrl) : '合同.pdf'
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 预览并生成合同:跳转合同预览页,签名后可确认生成 */
|
/** 生成/重新生成合同:弹出选项(直接签名 / 分享签名) */
|
||||||
function handlePreviewContract() {
|
function handlePreviewContract() {
|
||||||
const id = props.id || formData.value.id
|
const id = props.id || formData.value.id
|
||||||
if (!id) {
|
if (!id) {
|
||||||
toast.show('请先保存订单后再生成合同')
|
toast.show('请先保存订单后再生成合同')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (formData.value.productType !== '00') {
|
if (formData.value.productType !== '00' && formData.value.productType !== '02') {
|
||||||
toast.show('当前产品类别不支持生成合同')
|
toast.show('当前产品类别不支持生成合同,仅产品类别为 00 或 02 时可生成合同')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uni.navigateTo({
|
uni.showActionSheet({
|
||||||
url: `/pages/car/renewalorder/contract-preview/index?id=${id}`,
|
itemList: ['直接签名', '分享签名'],
|
||||||
|
success: (res) => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/contract-preview/index?id=${id}`,
|
||||||
|
})
|
||||||
|
} else if (res.tapIndex === 1) {
|
||||||
|
doOpenShareSign(Number(id))
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 分享签名:若有合同则先清空,再创建令牌并跳转分享页 */
|
||||||
|
async function doOpenShareSign(id: number) {
|
||||||
|
try {
|
||||||
|
const hadContract = !!formData.value.contractUrl
|
||||||
|
if (hadContract) {
|
||||||
|
await clearContractAndSignature(id)
|
||||||
|
formData.value.contractUrl = undefined
|
||||||
|
formData.value.customerSignatureUrl = undefined
|
||||||
|
toast.show('已清空合同与签名,请分享链接给客户签名')
|
||||||
|
}
|
||||||
|
const res = await createSignToken(id) as { data?: { signUrl?: string }; signUrl?: string }
|
||||||
|
const signUrl = res?.data?.signUrl ?? res?.signUrl
|
||||||
|
if (!signUrl) {
|
||||||
|
toast.show('生成签名链接失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/sign-share/index?signUrl=${encodeURIComponent(signUrl)}`,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
toast.error('操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 处理合同下载并打开 */
|
/** 处理合同下载并打开 */
|
||||||
function handleContractDownload() {
|
function handleContractDownload() {
|
||||||
if (!formData.value.contractUrl) {
|
if (!formData.value.contractUrl) {
|
||||||
@@ -817,15 +930,37 @@ async function getDetail() {
|
|||||||
try {
|
try {
|
||||||
const orderId = copyId.value || Number(props.id)
|
const orderId = copyId.value || Number(props.id)
|
||||||
const data = await getRenewalOrder(orderId)
|
const data = await getRenewalOrder(orderId)
|
||||||
// 处理发票日期
|
// 处理发票日期 - 先设置一个默认值,避免组件初始化时收到 undefined
|
||||||
|
const getDefaultDate = () => {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先设置默认值
|
||||||
|
formData.value.invoiceDate = getDefaultDate()
|
||||||
|
|
||||||
|
// 然后处理实际日期
|
||||||
if (data.invoiceDate) {
|
if (data.invoiceDate) {
|
||||||
|
let processedDate: string | null = null
|
||||||
if (typeof data.invoiceDate === 'string') {
|
if (typeof data.invoiceDate === 'string') {
|
||||||
formData.value.invoiceDate = data.invoiceDate.split(' ')[0] // 只取日期部分
|
const dateStr = data.invoiceDate.split(' ')[0] // 只取日期部分
|
||||||
|
// 验证日期格式,确保符合 YYYY-MM-DD
|
||||||
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
|
||||||
|
processedDate = dateStr
|
||||||
|
}
|
||||||
} else if (data.invoiceDate instanceof Date) {
|
} else if (data.invoiceDate instanceof Date) {
|
||||||
const year = data.invoiceDate.getFullYear()
|
const year = data.invoiceDate.getFullYear()
|
||||||
const month = String(data.invoiceDate.getMonth() + 1).padStart(2, '0')
|
const month = String(data.invoiceDate.getMonth() + 1).padStart(2, '0')
|
||||||
const day = String(data.invoiceDate.getDate()).padStart(2, '0')
|
const day = String(data.invoiceDate.getDate()).padStart(2, '0')
|
||||||
formData.value.invoiceDate = `${year}-${month}-${day}`
|
processedDate = `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果处理后的日期有效,使用它;否则保持默认值
|
||||||
|
if (processedDate && /^\d{4}-\d{2}-\d{2}$/.test(processedDate)) {
|
||||||
|
formData.value.invoiceDate = processedDate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 处理多张图片的 JSON 数组字段:如果后端返回的是字符串,需要解析为数组
|
// 处理多张图片的 JSON 数组字段:如果后端返回的是字符串,需要解析为数组
|
||||||
@@ -850,28 +985,114 @@ async function getDetail() {
|
|||||||
data.businessInsurancePolicyUrls = []
|
data.businessInsurancePolicyUrls = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 如果是复制创建,清除主键和合同路径等与原订单绑定的信息
|
// 如果是复制创建,清除主键、合同路径和所有图片相关字段
|
||||||
if (copyId.value) {
|
if (copyId.value) {
|
||||||
|
// 确保发票日期格式正确,如果为空或无效则设置为当前日期
|
||||||
|
let invoiceDate = data.invoiceDate
|
||||||
|
if (!invoiceDate || invoiceDate === 'Invalid Date' || invoiceDate === 'null' || invoiceDate === 'undefined') {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
invoiceDate = `${year}-${month}-${day}`
|
||||||
|
} else if (typeof invoiceDate === 'string') {
|
||||||
|
// 确保日期格式为 YYYY-MM-DD
|
||||||
|
invoiceDate = invoiceDate.split(' ')[0]
|
||||||
|
// 验证日期格式
|
||||||
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(invoiceDate)) {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
invoiceDate = `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const copyData: any = {
|
const copyData: any = {
|
||||||
...data,
|
...data,
|
||||||
id: undefined,
|
id: undefined,
|
||||||
contractUrl: '',
|
contractUrl: '',
|
||||||
|
invoiceDate: invoiceDate || (() => {
|
||||||
|
// 如果发票日期仍然无效,设置为当前日期
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
})(),
|
||||||
|
// 清空所有图片相关字段
|
||||||
|
customerSignatureUrl: undefined,
|
||||||
|
idCardFrontUrl: undefined,
|
||||||
|
idCardBackUrl: undefined,
|
||||||
|
drivingLicenseUrl: undefined,
|
||||||
|
certificateOfConformityUrl: undefined,
|
||||||
|
odometerPhotoUrl: undefined,
|
||||||
|
nameplatePhotoUrl: undefined,
|
||||||
|
carInvoiceUrls: [],
|
||||||
|
purchaseTaxInvoiceUrls: [],
|
||||||
|
businessInsurancePolicyUrls: [],
|
||||||
}
|
}
|
||||||
|
// 确保 invoiceDate 格式正确
|
||||||
|
if (!copyData.invoiceDate || !/^\d{4}-\d{2}-\d{2}$/.test(copyData.invoiceDate)) {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
copyData.invoiceDate = `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
// 确保 invoiceDate 是有效的字符串
|
||||||
|
if (!copyData.invoiceDate || typeof copyData.invoiceDate !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(copyData.invoiceDate)) {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
copyData.invoiceDate = `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
formData.value = copyData
|
formData.value = copyData
|
||||||
|
// 使用 nextTick 确保组件正确更新,然后再次验证日期值
|
||||||
|
await nextTick()
|
||||||
|
// 强制确保日期值有效
|
||||||
|
if (!formData.value.invoiceDate || typeof formData.value.invoiceDate !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(formData.value.invoiceDate)) {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
formData.value.invoiceDate = `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
|
// 复制创建模式下,清空所有文件列表
|
||||||
|
customerSignatureFileList.value = []
|
||||||
|
idCardFrontFileList.value = []
|
||||||
|
idCardBackFileList.value = []
|
||||||
|
drivingLicenseFileList.value = []
|
||||||
|
certificateOfConformityFileList.value = []
|
||||||
|
odometerPhotoFileList.value = []
|
||||||
|
nameplatePhotoFileList.value = []
|
||||||
|
carInvoiceFileList.value = []
|
||||||
|
purchaseTaxInvoiceFileList.value = []
|
||||||
|
businessInsurancePolicyFileList.value = []
|
||||||
} else {
|
} else {
|
||||||
|
// 编辑模式下,确保发票日期有效
|
||||||
|
if (!data.invoiceDate || !/^\d{4}-\d{2}-\d{2}$/.test(data.invoiceDate)) {
|
||||||
|
const today = new Date()
|
||||||
|
const year = today.getFullYear()
|
||||||
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
|
data.invoiceDate = `${year}-${month}-${day}`
|
||||||
|
}
|
||||||
formData.value = data
|
formData.value = data
|
||||||
|
// 编辑模式下,初始化文件列表
|
||||||
|
customerSignatureFileList.value = urlToFileList(data.customerSignatureUrl)
|
||||||
|
idCardFrontFileList.value = urlToFileList(data.idCardFrontUrl)
|
||||||
|
idCardBackFileList.value = urlToFileList(data.idCardBackUrl)
|
||||||
|
drivingLicenseFileList.value = urlToFileList(data.drivingLicenseUrl)
|
||||||
|
certificateOfConformityFileList.value = urlToFileList(data.certificateOfConformityUrl)
|
||||||
|
odometerPhotoFileList.value = urlToFileList(data.odometerPhotoUrl)
|
||||||
|
nameplatePhotoFileList.value = urlToFileList(data.nameplatePhotoUrl)
|
||||||
|
carInvoiceFileList.value = urlToFileList(data.carInvoiceUrls)
|
||||||
|
purchaseTaxInvoiceFileList.value = urlToFileList(data.purchaseTaxInvoiceUrls)
|
||||||
|
businessInsurancePolicyFileList.value = urlToFileList(data.businessInsurancePolicyUrls)
|
||||||
}
|
}
|
||||||
// 初始化文件列表
|
|
||||||
customerSignatureFileList.value = urlToFileList(data.customerSignatureUrl)
|
|
||||||
idCardFrontFileList.value = urlToFileList(data.idCardFrontUrl)
|
|
||||||
idCardBackFileList.value = urlToFileList(data.idCardBackUrl)
|
|
||||||
drivingLicenseFileList.value = urlToFileList(data.drivingLicenseUrl)
|
|
||||||
certificateOfConformityFileList.value = urlToFileList(data.certificateOfConformityUrl)
|
|
||||||
odometerPhotoFileList.value = urlToFileList(data.odometerPhotoUrl)
|
|
||||||
nameplatePhotoFileList.value = urlToFileList(data.nameplatePhotoUrl)
|
|
||||||
carInvoiceFileList.value = urlToFileList(data.carInvoiceUrls)
|
|
||||||
purchaseTaxInvoiceFileList.value = urlToFileList(data.purchaseTaxInvoiceUrls)
|
|
||||||
businessInsurancePolicyFileList.value = urlToFileList(data.businessInsurancePolicyUrls)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取订单详情失败:', error)
|
console.error('获取订单详情失败:', error)
|
||||||
toast.show('获取订单详情失败')
|
toast.show('获取订单详情失败')
|
||||||
@@ -889,9 +1110,36 @@ async function handleSubmit() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 必传文件校验:行驶证、购车发票、购置税凭证、身份证正反面
|
||||||
|
if (!formData.value.drivingLicenseUrl) {
|
||||||
|
toast.show('请上传行驶证')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.carInvoiceUrls?.length) {
|
||||||
|
toast.show('请上传购车发票')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.purchaseTaxInvoiceUrls?.length) {
|
||||||
|
toast.show('请上传购置税凭证')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.idCardFrontUrl) {
|
||||||
|
toast.show('请上传身份证正面')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!formData.value.idCardBackUrl) {
|
||||||
|
toast.show('请上传身份证反面')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
const data = { ...formData.value }
|
const data = { ...formData.value }
|
||||||
|
// 确保 productType 被正确传递
|
||||||
|
if (!data.productType && formData.value.productType) {
|
||||||
|
data.productType = formData.value.productType
|
||||||
|
}
|
||||||
|
|
||||||
// 复制创建和新增都走新增接口
|
// 复制创建和新增都走新增接口
|
||||||
if (props.id && !copyId.value) {
|
if (props.id && !copyId.value) {
|
||||||
await updateRenewalOrder(data)
|
await updateRenewalOrder(data)
|
||||||
@@ -911,13 +1159,43 @@ async function handleSubmit() {
|
|||||||
} else {
|
} else {
|
||||||
const res = (await createRenewalOrder(data)) as unknown
|
const res = (await createRenewalOrder(data)) as unknown
|
||||||
const newId = (res as { data?: number })?.data ?? (res as number)
|
const newId = (res as { data?: number })?.data ?? (res as number)
|
||||||
const needContract = formData.value.productType === '00' && newId
|
// 检查产品类别是否为 00 或 02
|
||||||
|
const productType = data.productType || formData.value.productType
|
||||||
|
const needContract = (productType === '00' || productType === '02') && newId
|
||||||
|
|
||||||
|
console.log('表单提交 - productType:', productType, 'needContract:', needContract, 'id:', newId, 'data:', data)
|
||||||
|
|
||||||
if (needContract) {
|
if (needContract) {
|
||||||
|
// 新增完成 → 弹出选项:直接签名 / 分享签名
|
||||||
uni.setStorageSync('renewalorder_list_need_refresh', true)
|
uni.setStorageSync('renewalorder_list_need_refresh', true)
|
||||||
uni.navigateTo({
|
toast.show('订单已创建,请选择签名方式')
|
||||||
url: `/pages/car/renewalorder/contract-preview/index?id=${newId}&from=form_create`,
|
uni.showActionSheet({
|
||||||
|
itemList: ['直接签名', '分享签名'],
|
||||||
|
success: async (res) => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/contract-preview/index?id=${newId}&from=form_create`,
|
||||||
|
})
|
||||||
|
toast.show('请完成客户签名后生成合同')
|
||||||
|
} else if (res.tapIndex === 1) {
|
||||||
|
try {
|
||||||
|
const tokenRes = await createSignToken(newId) as { data?: { signUrl?: string }; signUrl?: string }
|
||||||
|
const signUrl = tokenRes?.data?.signUrl ?? tokenRes?.signUrl
|
||||||
|
if (!signUrl) {
|
||||||
|
toast.show('生成签名链接失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/sign-share/index?signUrl=${encodeURIComponent(signUrl)}`,
|
||||||
|
})
|
||||||
|
toast.show('请分享链接给客户签名,签名成功后合同将自动生成')
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
toast.error('操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
toast.show('订单已创建,请完成客户签名后生成合同')
|
|
||||||
} else {
|
} else {
|
||||||
toast.success(copyId.value ? '复制创建成功' : '新增成功')
|
toast.success(copyId.value ? '复制创建成功' : '新增成功')
|
||||||
uni.setStorageSync('renewalorder_list_need_refresh', true)
|
uni.setStorageSync('renewalorder_list_need_refresh', true)
|
||||||
@@ -959,17 +1237,32 @@ onShow(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/** 初始化 */
|
/** 初始化 */
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await Promise.all([getStoreList(), getProductList()])
|
await Promise.all([getStoreList(), getProductList()])
|
||||||
// 新增:默认选择门店第一项(编辑不覆盖)
|
// 新增:默认选择当前用户所在门店;车辆购买方默认为当前用户门店名称,均可修改
|
||||||
if ((!props.id && !copyId.value) && !formData.value.storeId && storeList.value.length > 0) {
|
if (!props.id && !copyId.value && storeList.value.length > 0) {
|
||||||
formData.value.storeId = storeList.value[0].id
|
if (userStore.storeId != null && storeList.value.some((s: StoreVO) => s.id === userStore.storeId)) {
|
||||||
|
formData.value.storeId = userStore.storeId
|
||||||
|
formData.value.serviceBuyer = userStore.storeName || storeList.value.find((s: StoreVO) => s.id === userStore.storeId)?.storeName || ''
|
||||||
|
} else {
|
||||||
|
if (!formData.value.storeId) formData.value.storeId = storeList.value[0].id
|
||||||
|
if (!formData.value.serviceBuyer) formData.value.serviceBuyer = userStore.storeName || storeList.value[0].storeName || ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 新增:默认选择证件类型字典第一项(编辑不覆盖)
|
// 新增:默认选择证件类型字典第一项(编辑不覆盖)
|
||||||
if ((!props.id && !copyId.value) && !formData.value.certType && certTypeOptions.value.length > 0) {
|
if ((!props.id && !copyId.value) && !formData.value.certType && certTypeOptions.value.length > 0) {
|
||||||
formData.value.certType = certTypeOptions.value[0].value
|
formData.value.certType = certTypeOptions.value[0].value
|
||||||
}
|
}
|
||||||
|
// 新增:默认选择结算方式为 '00'(编辑不覆盖)
|
||||||
|
if ((!props.id && !copyId.value) && !formData.value.settlementMethod) {
|
||||||
|
formData.value.settlementMethod = '00'
|
||||||
|
}
|
||||||
|
// 新增:录单人默认当前登录用户名称,可修改
|
||||||
|
if (!props.id && !copyId.value) {
|
||||||
|
formData.value.inputUser = userStore.userInfo?.nickname || userStore.userInfo?.username || ''
|
||||||
|
}
|
||||||
// 如果是编辑模式或复制创建模式,加载详情
|
// 如果是编辑模式或复制创建模式,加载详情
|
||||||
if (props.id || copyId.value) {
|
if (props.id || copyId.value) {
|
||||||
await getDetail()
|
await getDetail()
|
||||||
@@ -978,6 +1271,10 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.invoice-date-picker-value {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
.contract-area {
|
.contract-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -20,20 +20,24 @@
|
|||||||
<view class="relative p-24rpx" @click="handleDetail(item)">
|
<view class="relative p-24rpx" @click="handleDetail(item)">
|
||||||
<view class="flex items-center justify-between mb-16rpx">
|
<view class="flex items-center justify-between mb-16rpx">
|
||||||
<view class="text-32rpx text-[#333] font-semibold">
|
<view class="text-32rpx text-[#333] font-semibold">
|
||||||
{{ item.licensePlate || '-' }}
|
{{ item.serviceBuyer || '-' }}
|
||||||
</view>
|
</view>
|
||||||
<view class="text-24rpx text-[#999]">
|
<view class="text-24rpx text-[#999]">
|
||||||
{{ item.createTime ? formatDate(item.createTime) : '-' }}
|
{{ item.createTime ? formatDate(item.createTime) : '-' }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="space-y-12rpx text-26rpx text-[#666]">
|
<view class="space-y-12rpx text-26rpx text-[#666]">
|
||||||
|
<view class="flex items-center justify-between">
|
||||||
|
<text>车牌号:</text>
|
||||||
|
<text>{{ item.licensePlate || '-' }}</text>
|
||||||
|
</view>
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
<text>品牌车型:</text>
|
<text>品牌车型:</text>
|
||||||
<text>{{ item.carBrand }} {{ item.carModel }}</text>
|
<text>{{ item.carBrand }} {{ item.carModel }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between" @click.stop @click="handleEdit(item)">
|
||||||
<text>服务购买方:</text>
|
<text>服务购买方:</text>
|
||||||
<text>{{ item.serviceBuyer || '-' }}</text>
|
<text class="text-[#409eff] underline">{{ item.serviceBuyer || '-' }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
<text>联系电话:</text>
|
<text>联系电话:</text>
|
||||||
@@ -43,10 +47,18 @@
|
|||||||
<text>门店:</text>
|
<text>门店:</text>
|
||||||
<text>{{ item.storeName || '-' }}</text>
|
<text>{{ item.storeName || '-' }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="flex items-center justify-between">
|
||||||
|
<text>产品年限:</text>
|
||||||
|
<text>{{ item.originalWarrantyYears || '-' }}</text>
|
||||||
|
</view>
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
<text>产品费用:</text>
|
<text>产品费用:</text>
|
||||||
<text class="text-[#1890ff]">¥{{ item.productFee || 0 }}</text>
|
<text class="text-[#1890ff]">¥{{ item.productFee || 0 }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="flex items-center justify-between">
|
||||||
|
<text>结算方式:</text>
|
||||||
|
<text>{{ getSettlementMethodLabel(item.settlementMethod) }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 底部操作按钮 -->
|
<!-- 底部操作按钮 -->
|
||||||
@@ -100,6 +112,8 @@ import { useToast } from 'wot-design-uni'
|
|||||||
import { navigateBackPlus } from '@/utils'
|
import { navigateBackPlus } from '@/utils'
|
||||||
import { formatDate } from '@/utils/date'
|
import { formatDate } from '@/utils/date'
|
||||||
import SearchForm from './components/search-form.vue'
|
import SearchForm from './components/search-form.vue'
|
||||||
|
import { getDictLabel } from '@/hooks/useDict'
|
||||||
|
import { DICT_TYPE } from '@/utils/constants'
|
||||||
|
|
||||||
definePage({
|
definePage({
|
||||||
style: {
|
style: {
|
||||||
@@ -177,6 +191,19 @@ function handleDetail(item: RenewalOrderVO) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 编辑订单 */
|
||||||
|
function handleEdit(item: RenewalOrderVO) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/car/renewalorder/form/index?id=${item.id}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取结算方式字典标签 */
|
||||||
|
function getSettlementMethodLabel(value?: string) {
|
||||||
|
if (!value) return '-'
|
||||||
|
return getDictLabel(DICT_TYPE.CAR_RENEWAL_PAY_METHOD, value) || value
|
||||||
|
}
|
||||||
|
|
||||||
/** 复制创建订单:基于原订单预填表单,进入新增模式 */
|
/** 复制创建订单:基于原订单预填表单,进入新增模式 */
|
||||||
function handleCopy(item: RenewalOrderVO) {
|
function handleCopy(item: RenewalOrderVO) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
|
|||||||
133
src/pages/car/renewalorder/sign-share/index.vue
Normal file
133
src/pages/car/renewalorder/sign-share/index.vue
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<view class="yd-page-container sign-share-page">
|
||||||
|
<view v-if="fullUrl" class="sign-share-content">
|
||||||
|
<view class="tip-box">
|
||||||
|
<text class="tip-text">请将下方链接或二维码分享给客户,客户打开链接完成签名后合同将自动生成。</text>
|
||||||
|
</view>
|
||||||
|
<view class="link-box">
|
||||||
|
<text class="link-label">签名链接</text>
|
||||||
|
<text class="link-value" selectable>{{ fullUrl }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="tip-small">链接有效期 12 小时</view>
|
||||||
|
<wd-button type="primary" block class="copy-btn" @click="handleCopy">
|
||||||
|
复制链接
|
||||||
|
</wd-button>
|
||||||
|
</view>
|
||||||
|
<view v-else class="loading-wrap">
|
||||||
|
<view class="loading-dot" />
|
||||||
|
<text class="text-28rpx text-[#999] mt-24rpx">加载中...</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useToast } from 'wot-design-uni'
|
||||||
|
import { getEnvBaseUrlRoot } from '@/utils'
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationBarTitleText: '分享签名',
|
||||||
|
navigationStyle: 'default',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const toast = useToast()
|
||||||
|
const fullUrl = ref('')
|
||||||
|
|
||||||
|
function handleCopy() {
|
||||||
|
if (!fullUrl.value) return
|
||||||
|
uni.setClipboardData({
|
||||||
|
data: fullUrl.value,
|
||||||
|
success: () => {
|
||||||
|
toast.success('链接已复制')
|
||||||
|
setTimeout(() => {
|
||||||
|
// 关闭分享页 + 上一页(新增/编辑/详情),直接回到列表
|
||||||
|
uni.navigateBack({ delta: 2 })
|
||||||
|
}, 500)
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
toast.error('复制失败')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
let signUrl = options?.signUrl || ''
|
||||||
|
if (signUrl) {
|
||||||
|
try {
|
||||||
|
signUrl = decodeURIComponent(signUrl)
|
||||||
|
} catch {
|
||||||
|
// 已为明文路径则忽略
|
||||||
|
}
|
||||||
|
const base = getEnvBaseUrlRoot()
|
||||||
|
fullUrl.value = base + (signUrl.startsWith('/') ? signUrl : `/${signUrl}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.sign-share-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.sign-share-content {
|
||||||
|
padding: 32rpx;
|
||||||
|
}
|
||||||
|
.tip-box {
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
padding: 24rpx;
|
||||||
|
background: #f0f9ff;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
.tip-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.link-box {
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
padding: 24rpx;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
|
.link-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
.link-value {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #333;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.tip-small {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
}
|
||||||
|
.copy-btn {
|
||||||
|
margin-top: 24rpx;
|
||||||
|
}
|
||||||
|
.loading-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 80rpx 0;
|
||||||
|
}
|
||||||
|
.loading-dot {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
border: 4rpx solid #e5e5e5;
|
||||||
|
border-top-color: #3b82f6;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -55,6 +55,8 @@ const BPM_DICT = {
|
|||||||
/** ========== CAR - 车辆模块 ========== */
|
/** ========== CAR - 车辆模块 ========== */
|
||||||
const CAR_DICT = {
|
const CAR_DICT = {
|
||||||
CAR_RENEWAL_PRODUCT_TYPE: 'car_renewal_product_type', // 续保产品类别
|
CAR_RENEWAL_PRODUCT_TYPE: 'car_renewal_product_type', // 续保产品类别
|
||||||
|
CAR_RENEWAL_PAY_METHOD: 'car_renewal_pay_method', // 续保结算方式
|
||||||
|
CAR_RENEWAL_YEAR: 'car_renewal_year', // 续保生效年限
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
/** 字典类型枚举 - 统一导出 */
|
/** 字典类型枚举 - 统一导出 */
|
||||||
|
|||||||
@@ -123,9 +123,9 @@ export function getEnvBaseUrl() {
|
|||||||
|
|
||||||
// # 有些同学可能需要在微信小程序里面根据 develop、trial、release 分别设置上传地址,参考代码如下。
|
// # 有些同学可能需要在微信小程序里面根据 develop、trial、release 分别设置上传地址,参考代码如下。
|
||||||
// TODO @芋艿:这个后续也要调整。
|
// TODO @芋艿:这个后续也要调整。
|
||||||
const VITE_SERVER_BASEURL__WEIXIN_DEVELOP = 'http://1.14.158.154:48080/admin-api'
|
const VITE_SERVER_BASEURL__WEIXIN_DEVELOP = 'https://api.tuanbanlv.com/admin-api'
|
||||||
const VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'http://1.14.158.154:48080/admin-api'
|
const VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'https://api.tuanbanlv.com/admin-api'
|
||||||
const VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'http://1.14.158.154:48080/admin-api'
|
const VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'https://api.tuanbanlv.com/admin-api'
|
||||||
|
|
||||||
// 微信小程序端环境区分
|
// 微信小程序端环境区分
|
||||||
if (isMpWeixin) {
|
if (isMpWeixin) {
|
||||||
@@ -150,17 +150,18 @@ export function getEnvBaseUrl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据环境变量,获取基础路径的根路径,比如 http://1.14.158.154:48080
|
* 根据环境变量,获取基础路径的根路径,比如 https://api.tuanbanlv.com
|
||||||
*
|
*
|
||||||
* add by 芋艿:用户类似 websocket 这种需要根路径的场景
|
* add by 芋艿:用户类似 websocket 这种需要根路径的场景
|
||||||
|
* 注意:小程序环境无 URL 构造函数,使用正则解析
|
||||||
*
|
*
|
||||||
* @return 根路径
|
* @return 根路径
|
||||||
*/
|
*/
|
||||||
export function getEnvBaseUrlRoot() {
|
export function getEnvBaseUrlRoot() {
|
||||||
const baseUrl = getEnvBaseUrl()
|
const baseUrl = getEnvBaseUrl()
|
||||||
// 提取根路径
|
// 小程序环境 URL 可能不可用,用正则提取 origin
|
||||||
const urlObj = new URL(baseUrl)
|
const match = baseUrl.match(/^(https?:\/\/[^/]+)/)
|
||||||
return urlObj.origin
|
return match ? match[1] : baseUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user