modify-info.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. <route lang="json5" type="page">
  2. {
  3. layout: 'default',
  4. style: {
  5. navigationBarTitleText: '修改基本信息',
  6. },
  7. }
  8. </route>
  9. <template>
  10. <view class="bg-gray-100 min-h-screen pb-20">
  11. <!-- 修改说明 -->
  12. <view class="bg-white px-4 py-4 mb-3 shadow-sm">
  13. <view class="flex items-center mb-3">
  14. <view class="text-lg font-bold text-gray-800">修改说明</view>
  15. <view class="ml-2 flex-1 h-px bg-gray-100"></view>
  16. </view>
  17. <view class="rules-text text-sm text-gray-600 space-y-1">
  18. <view>1. 请根据审核反馈,修改相关信息;</view>
  19. <view>2. 修改完成后,系统将重新进行审核;</view>
  20. <view>3. 审核通过后,您可以使用优惠券进行下单。</view>
  21. <view class="text-orange-600">
  22. 4. 系统将自动回显您的手机号,其他信息按审核反馈修改,请重新填写。
  23. </view>
  24. </view>
  25. </view>
  26. <!-- 表单区域 -->
  27. <view class="bg-white px-4 py-4 shadow-sm">
  28. <view class="flex items-center mb-4">
  29. <view class="text-lg font-bold text-gray-800">基本信息</view>
  30. <view class="ml-2 flex-1 h-px bg-gray-100"></view>
  31. </view>
  32. <wd-form ref="formRef" :model="formData">
  33. <wd-cell-group border>
  34. <!-- 用户类型 -->
  35. <wd-cell
  36. title="用户类型"
  37. title-width="100px"
  38. prop="userstype"
  39. required
  40. custom-class="custom-cell"
  41. >
  42. <wd-radio-group
  43. v-model="formData.userstype"
  44. @change="handleUserTypeChange"
  45. inline
  46. shape="dot"
  47. :rules="[{ required: true, message: '请选择用户类型' }]"
  48. >
  49. <wd-radio value="个人">个人</wd-radio>
  50. <wd-radio value="企业">企业</wd-radio>
  51. </wd-radio-group>
  52. </wd-cell>
  53. <!-- 姓名/企业名称 -->
  54. <wd-input
  55. :label="usersnameLabel"
  56. label-width="100px"
  57. prop="usersname"
  58. required
  59. v-model="formData.usersname"
  60. :placeholder="`请输入${usersnameLabel}`"
  61. clearable
  62. no-border
  63. :rules="[{ required: true, message: `请输入${usersnameLabel}` }]"
  64. />
  65. <!-- 地址 -->
  66. <wd-input
  67. :label="addressLabel"
  68. label-width="100px"
  69. prop="usersaddress"
  70. required
  71. v-model="formData.usersaddress"
  72. :placeholder="`请输入${addressLabel}`"
  73. clearable
  74. no-border
  75. :rules="[{ required: true, message: `请输入${addressLabel}` }]"
  76. />
  77. <!-- 证件号 -->
  78. <wd-input
  79. :label="idNumberLabel"
  80. label-width="100px"
  81. prop="idNumber"
  82. required
  83. v-model="formData.idNumber"
  84. :placeholder="`请输入${idNumberLabel}`"
  85. clearable
  86. no-border
  87. :rules="[{ required: true, message: `请输入${idNumberLabel}` }]"
  88. />
  89. <!-- 证件照片上传 -->
  90. <wd-cell
  91. :title="idPhotoLabel"
  92. title-width="100px"
  93. prop="idPhotoIds"
  94. required
  95. custom-class="custom-cell"
  96. >
  97. <view class="flex-1">
  98. <!-- 个人身份证上传 -->
  99. <template v-if="formData.userstype === '个人'">
  100. <UploadComponent
  101. v-model="formData.idCardFiles"
  102. v-model:fileIds="formData.idCardIds"
  103. :limit="1"
  104. attmodel="coupon_identity"
  105. attpath="/coupon_identity/"
  106. modelStats="idCardIds"
  107. message="请上传身份证照片"
  108. tips="请上传身份证正面照片"
  109. />
  110. </template>
  111. <!-- 企业营业执照上传 -->
  112. <template v-else>
  113. <UploadComponent
  114. v-model="formData.businessLicenseFiles"
  115. v-model:fileIds="formData.businessLicenseIds"
  116. :limit="1"
  117. attmodel="coupon_identity"
  118. attpath="/coupon_identity/"
  119. modelStats="businessLicenseIds"
  120. message="请上传营业执照照片"
  121. />
  122. </template>
  123. </view>
  124. </wd-cell>
  125. <!-- 购机者照片上传 (可选) -->
  126. <wd-cell title="购机者照片" title-width="100px" custom-class="custom-cell">
  127. <view class="flex-1">
  128. <UploadComponent
  129. v-model="formData.buyerPhoto"
  130. v-model:fileIds="formData.buyerPhotoIds"
  131. :limit="1"
  132. :required="false"
  133. attmodel="coupon_buyer"
  134. attpath="/coupon_buyer/"
  135. modelStats="buyerPhotoIds"
  136. message="请上传购机者照片"
  137. tips="用于确认购机者身份"
  138. />
  139. </view>
  140. </wd-cell>
  141. <!-- 手机号 -->
  142. <wd-input
  143. label="手机号"
  144. label-width="100px"
  145. prop="phone"
  146. required
  147. v-model="formData.phone"
  148. placeholder="请输入您的手机号码"
  149. clearable
  150. no-border
  151. :rules="[
  152. { required: true, message: '请输入手机号码' },
  153. { required: false, pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' },
  154. ]"
  155. @blur="validatePhone"
  156. />
  157. </wd-cell-group>
  158. </wd-form>
  159. </view>
  160. <!-- 提交按钮 -->
  161. <view class="fixed-bottom bg-white p-4 border-t border-gray-100">
  162. <wd-button type="primary" block size="large" @click="handleSubmit" :loading="submitLoading">
  163. 确认保存
  164. </wd-button>
  165. </view>
  166. <!-- loading -->
  167. <wd-overlay :show="overlayShow">
  168. <view class="wrapper w-full h-full flex items-center justify-center">
  169. <wd-loading />
  170. </view>
  171. </wd-overlay>
  172. </view>
  173. </template>
  174. <script lang="ts" setup>
  175. import { reactive, ref, computed, onMounted } from 'vue'
  176. import { useMessage } from 'wot-design-uni'
  177. import { onLoad } from '@dcloudio/uni-app'
  178. import UploadComponent from '@/components/UploadComponent.vue'
  179. import { useCouponStore } from '@/store/coupon'
  180. import { useUserStore } from '@/store/user'
  181. import { useFileStore } from '@/store/file'
  182. const message = useMessage()
  183. const couponStore = useCouponStore()
  184. const userStore = useUserStore()
  185. const fileStore = useFileStore()
  186. // 页面参数
  187. const coupon2sid = ref('')
  188. const formRef = ref<any>()
  189. const formData = reactive({
  190. userstype: '个人', // 用户类型,默认个人
  191. usersname: '', // 姓名或企业名称
  192. usersaddress: '', // 地址
  193. idNumber: '', // 证件号
  194. // 身份证照片(个人用户)
  195. idCardFiles: [], // 身份证照片文件列表
  196. idCardIds: [], // 身份证照片ID列表
  197. // 营业执照(企业用户)
  198. businessLicenseFiles: [], // 营业执照照片文件列表
  199. businessLicenseIds: [], // 营业执照照片ID列表
  200. // 购机者照片(可选)
  201. buyerPhoto: [], // 购机者照片文件列表
  202. buyerPhotoIds: [], // 购机者照片ID列表
  203. phone: '', // 手机号
  204. })
  205. // 优惠券详情数据
  206. const couponDetail = ref<any>(null)
  207. const usersnameLabel = computed(() => (formData.userstype === '个人' ? '姓名' : '企业名称'))
  208. const addressLabel = computed(() => (formData.userstype === '个人' ? '身份证地址' : '企业注册地址'))
  209. const idNumberLabel = computed(() =>
  210. formData.userstype === '个人' ? '身份证号' : '统一社会信用代码',
  211. )
  212. const idPhotoLabel = computed(() => (formData.userstype === '个人' ? '身份证正面' : '营业执照'))
  213. const overlayShow = ref(false)
  214. const submitLoading = ref(false)
  215. // 手机号验证相关
  216. const isPhoneValid = ref(false)
  217. const phoneReg = /^1[3-9]\d{9}$/
  218. function validatePhone() {
  219. if (!formData.phone) {
  220. isPhoneValid.value = false
  221. return
  222. }
  223. isPhoneValid.value = phoneReg.test(formData.phone)
  224. if (!isPhoneValid.value && formData.phone) {
  225. uni.showToast({ title: '请输入正确的手机号码', icon: 'none' })
  226. }
  227. }
  228. // 用户类型切换
  229. function handleUserTypeChange() {
  230. // 清空相关字段以便用户重新输入和校验
  231. formData.usersname = ''
  232. formData.usersaddress = ''
  233. formData.idNumber = ''
  234. // 清空证件照片上传
  235. if (formData.userstype === '个人') {
  236. formData.idCardFiles = []
  237. formData.idCardIds = []
  238. formData.businessLicenseFiles = []
  239. formData.businessLicenseIds = []
  240. } else {
  241. formData.idCardFiles = []
  242. formData.idCardIds = []
  243. formData.businessLicenseFiles = []
  244. formData.businessLicenseIds = []
  245. }
  246. // 清空购机者照片
  247. formData.buyerPhoto = []
  248. formData.buyerPhotoIds = []
  249. }
  250. // 获取并回显图片信息
  251. async function loadImageFiles() {
  252. try {
  253. // 获取身份证/营业执照图片
  254. const identityImages = await fileStore.getAttachmentList({
  255. attlsh: coupon2sid.value,
  256. attmodel: 'coupon_identity',
  257. })
  258. console.log('获取到的身份证/营业执照图片:', identityImages)
  259. // 获取购机者照片
  260. const buyerImages = await fileStore.getAttachmentList({
  261. attlsh: coupon2sid.value,
  262. attmodel: 'coupon_buyer',
  263. })
  264. console.log('获取到的购机者照片:', buyerImages)
  265. // 回显身份证/营业执照图片
  266. if (identityImages.length > 0) {
  267. if (formData.userstype === '个人') {
  268. // 个人用户回显身份证
  269. formData.idCardFiles = identityImages.map((img) => ({
  270. url: img.url,
  271. name: img.attorginname || '身份证照片',
  272. }))
  273. formData.idCardIds = identityImages.map((img) => ({
  274. url: img.url,
  275. id: img.attid,
  276. }))
  277. } else {
  278. // 企业用户回显营业执照
  279. formData.businessLicenseFiles = identityImages.map((img) => ({
  280. url: img.url,
  281. name: img.attorginname || '营业执照照片',
  282. }))
  283. formData.businessLicenseIds = identityImages.map((img) => ({
  284. url: img.url,
  285. id: img.attid,
  286. }))
  287. }
  288. }
  289. // 回显购机者照片
  290. if (buyerImages.length > 0) {
  291. formData.buyerPhoto = buyerImages.map((img) => ({
  292. url: img.url,
  293. name: img.attorginname || '购机者照片',
  294. }))
  295. formData.buyerPhotoIds = buyerImages.map((img) => ({
  296. url: img.url,
  297. id: img.attid,
  298. }))
  299. }
  300. console.log('回显的图片信息:', {
  301. identityImages,
  302. buyerImages,
  303. formData: {
  304. idCardFiles: formData.idCardFiles,
  305. idCardIds: formData.idCardIds,
  306. businessLicenseFiles: formData.businessLicenseFiles,
  307. businessLicenseIds: formData.businessLicenseIds,
  308. buyerPhoto: formData.buyerPhoto,
  309. buyerPhotoIds: formData.buyerPhotoIds,
  310. },
  311. })
  312. } catch (error) {
  313. console.error('获取图片信息失败:', error)
  314. }
  315. }
  316. // 提交表单
  317. async function handleSubmit() {
  318. try {
  319. const valid = await formRef.value.validate()
  320. if (!valid) {
  321. return
  322. }
  323. validatePhone()
  324. if (!isPhoneValid.value) {
  325. uni.showToast({ title: '请输入正确的手机号码', icon: 'none' })
  326. return
  327. }
  328. // 验证证件照片上传
  329. const hasUploadedFiles =
  330. formData.userstype === '个人'
  331. ? formData.idCardIds.length > 0
  332. : formData.businessLicenseIds.length > 0
  333. if (!hasUploadedFiles) {
  334. uni.showToast({
  335. title: `请上传${formData.userstype === '个人' ? '身份证照片' : '营业执照照片'}`,
  336. icon: 'none',
  337. })
  338. return
  339. }
  340. submitLoading.value = true
  341. overlayShow.value = true
  342. try {
  343. // 准备提交参数
  344. const submitParams: any = {
  345. coupon2sid: coupon2sid.value, // 优惠券ID
  346. userstype: formData.userstype, // 用户类型
  347. usersname: formData.usersname, // 姓名或企业名称
  348. usersaddress: formData.usersaddress, // 地址
  349. coupon2phone: formData.phone, // 手机号
  350. }
  351. // 根据用户类型添加证件号
  352. if (formData.userstype === '个人') {
  353. submitParams.usersidcardnumber = formData.idNumber // 身份证号
  354. } else {
  355. submitParams.usersshtyxydm = formData.idNumber // 统一社会信用代码
  356. }
  357. // 添加文件ID
  358. const fileIds = []
  359. // 添加身份证/营业执照文件ID
  360. if (formData.userstype === '个人' && formData.idCardIds.length > 0) {
  361. fileIds.push(...formData.idCardIds.map((item) => item.id))
  362. } else if (formData.userstype === '企业' && formData.businessLicenseIds.length > 0) {
  363. fileIds.push(...formData.businessLicenseIds.map((item) => item.id))
  364. }
  365. // 添加购机者照片文件ID(可选)
  366. if (formData.buyerPhotoIds.length > 0) {
  367. fileIds.push(...formData.buyerPhotoIds.map((item) => item.id))
  368. }
  369. if (fileIds.length > 0) {
  370. submitParams.filesid = fileIds.join(',')
  371. }
  372. console.log('提交参数:', submitParams)
  373. // 调用修改接口
  374. const result = await couponStore.getCoupon2Modify(submitParams)
  375. console.log('修改结果:', result)
  376. submitLoading.value = false
  377. overlayShow.value = false
  378. message
  379. .alert({
  380. msg: '信息修改成功!系统将重新审核您的优惠券。',
  381. title: '提示',
  382. confirmButtonText: '确定',
  383. })
  384. .then(() => {
  385. // 跳转回优惠券列表页面
  386. uni.navigateBack()
  387. })
  388. } catch (error) {
  389. console.error('提交修改失败:', error)
  390. submitLoading.value = false
  391. overlayShow.value = false
  392. message.alert({
  393. title: '提示',
  394. msg: '提交失败,请稍后重试',
  395. })
  396. }
  397. } catch (error) {
  398. console.error('修改信息出错:', error)
  399. submitLoading.value = false
  400. overlayShow.value = false
  401. }
  402. }
  403. onLoad(async (query: any) => {
  404. coupon2sid.value = query.coupon2sid || ''
  405. if (coupon2sid.value) {
  406. try {
  407. overlayShow.value = true
  408. // 获取优惠券详情
  409. const couponDetailResult = await couponStore.getCoupon2ViewDetailBySid({
  410. coupon2sid: coupon2sid.value,
  411. })
  412. if (couponDetailResult) {
  413. couponDetail.value = couponDetailResult
  414. // 回显表单数据
  415. if (couponDetail.value.usersphone) {
  416. formData.phone = couponDetail.value.usersphone
  417. }
  418. // 回显用户类型
  419. if (couponDetail.value.userstype) {
  420. formData.userstype = couponDetail.value.userstype
  421. }
  422. // 回显姓名/企业名称
  423. if (couponDetail.value.usersname) {
  424. formData.usersname = couponDetail.value.usersname
  425. }
  426. // 回显地址
  427. if (couponDetail.value.usersaddress) {
  428. formData.usersaddress = couponDetail.value.usersaddress
  429. }
  430. // 回显证件号
  431. if (couponDetail.value.usersidcardnumber) {
  432. formData.idNumber = couponDetail.value.usersidcardnumber
  433. } else if (couponDetail.value.usersshtyxydm) {
  434. formData.idNumber = couponDetail.value.usersshtyxydm
  435. }
  436. // 获取并回显图片信息
  437. await loadImageFiles()
  438. }
  439. } catch (error) {
  440. console.error('获取优惠券详情失败:', error)
  441. message.alert({
  442. title: '提示',
  443. msg: '获取优惠券信息失败,请稍后重试',
  444. })
  445. } finally {
  446. overlayShow.value = false
  447. }
  448. }
  449. })
  450. </script>
  451. <style lang="scss" scoped>
  452. .rules-text {
  453. line-height: 1.6;
  454. }
  455. .fixed-bottom {
  456. position: fixed;
  457. right: 0;
  458. bottom: 0;
  459. left: 0;
  460. z-index: 100;
  461. }
  462. // 针对 wd-field 内的 wd-input, wd-radio-group 等组件去除边框或调整样式
  463. :deep(.wd-cell-group .wd-input) {
  464. // If they don't have a border by default or if no-border is not working as expected
  465. // Example:
  466. // border-bottom: 1px solid #eee;
  467. }
  468. :deep(.wd-cell-group .wd-input__inner) {
  469. // If no-border was intended to remove internal padding/borders of wd-input for wd-field
  470. // We might not need this if wd-input itself looks fine as a direct child of wd-cell-group.
  471. // The no-border prop on wd-input might be sufficient.
  472. }
  473. // For wd-cell containing radio group or other custom layouts
  474. :deep(.custom-cell .wd-cell__value) {
  475. flex: 1; // Allow radio group or other content to take full width
  476. }
  477. :deep(.custom-cell .wd-radio-group) {
  478. // specific styles for radio group if needed
  479. }
  480. .wrapper {
  481. display: flex;
  482. align-items: center;
  483. justify-content: center;
  484. height: 100%;
  485. }
  486. </style>