NewCustomerForm.vue 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. <template>
  2. <a-modal :visible="visible" :title="editMode ? $t('customer.editCustomer') : $t('customer.addCustomer')"
  3. :loading="loading" @ok="handleSubmit" @cancel="handleCancel" :width="720">
  4. <a-tabs>
  5. <a-tab-pane key="1" :title="$t('customer.basicInfo')">
  6. <a-form :model="formData" :rules="rules" ref="formRef" :label-col-props="{ span: 6 }"
  7. :wrapper-col-props="{ span: 18 }">
  8. <a-divider>{{ $t('customer.basicInfoSection') }}</a-divider>
  9. <a-form-item field="customerInfo.customerCode" :label="$t('customer.customerCode')" required>
  10. <a-input v-model="formData.customerInfo.customerCode"
  11. :placeholder="$t('customer.enterCustomerCode')" :max-length="60" show-word-limit />
  12. </a-form-item>
  13. <a-form-item field="customerInfo.name" :label="$t('customer.customerName')" required>
  14. <a-input v-model="formData.customerInfo.name" :placeholder="$t('customer.enterCustomerName')"
  15. :max-length="60" show-word-limit />
  16. </a-form-item>
  17. <a-form-item field="userInfo.username" :label="$t('customer.accountNumber')" required>
  18. <a-input v-model="formData.userInfo.username" :placeholder="$t('customer.enterAccountNumber')"
  19. :max-length="60" show-word-limit />
  20. </a-form-item>
  21. <a-form-item field="userInfo.password" :label="$t('customer.password')" required>
  22. <a-input-password v-model="formData.userInfo.password"
  23. :placeholder="$t('customer.enterPassword')" :max-length="60" show-word-limit />
  24. <a-button type="primary" @click="generatePassword">{{ $t('customer.generatePassword')
  25. }}</a-button>
  26. </a-form-item>
  27. <a-form-item field="customerInfo.remark" :label="$t('customer.remark')">
  28. <a-input v-model="formData.customerInfo.remark" :placeholder="$t('customer.enterRemark')"
  29. :max-length="60" show-word-limit />
  30. </a-form-item>
  31. <a-form-item field="customerInfo.exTime" :label="$t('customer.validPeriod')" required>
  32. <a-date-picker v-model="formData.customerInfo.exTime"
  33. :placeholder="$t('customer.selectValidPeriod')" value-format="YYYY-MM-DD" />
  34. </a-form-item>
  35. <a-form-item field="userInfo.state" :label="$t('customer.statusName')" required>
  36. <a-radio-group v-model="formData.userInfo.state">
  37. <a-radio value="1">{{ $t('customer.status.normal') }}</a-radio>
  38. <a-radio value="2">{{ $t('customer.status.disabled') }}</a-radio>
  39. <a-radio value="3">{{ $t('customer.status.pending') }}</a-radio>
  40. <a-radio value="4">{{ $t('customer.status.suspended') }}</a-radio>
  41. </a-radio-group>
  42. </a-form-item>
  43. <a-divider>{{ $t('customer.smsInfoSection') }}</a-divider>
  44. <a-form-item field="customerInfo.smsSubCode" :label="$t('customer.smsSubCode')">
  45. <a-input v-model="formData.customerInfo.smsSubCode"
  46. :placeholder="$t('customer.enterSmsSubCode')" :max-length="60" show-word-limit />
  47. </a-form-item>
  48. <a-form-item field="customerInfo.smsName" :label="$t('customer.smsName')">
  49. <a-input v-model="formData.customerInfo.smsName" :placeholder="$t('customer.enterSmsName')"
  50. :max-length="60" show-word-limit />
  51. </a-form-item>
  52. <a-form-item field="customerInfo.loginSmsTemplate" :label="$t('customer.loginSmsTemplate')">
  53. <a-input v-model="formData.customerInfo.loginSmsTemplate"
  54. :placeholder="$t('customer.enterLoginSmsTemplate')" :max-length="60" show-word-limit />
  55. </a-form-item>
  56. <a-form-item field="customerInfo.alarmSmsTemplate" :label="$t('customer.alarmSmsTemplate')">
  57. <a-input v-model="formData.customerInfo.alarmSmsTemplate"
  58. :placeholder="$t('customer.enterAlarmSmsTemplate')" :max-length="60" show-word-limit />
  59. </a-form-item>
  60. </a-form>
  61. </a-tab-pane>
  62. <a-tab-pane key="2" :title="$t('customer.accountManagement')">
  63. <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
  64. <a-form-item field="customerProperty.amount" :label="$t('customer.accountBalance')">
  65. <a-input-number v-model="formData.customerProperty.amount" :min="0" :precision="2" :step="100"
  66. :suffix="$t('customer.currency')" />
  67. </a-form-item>
  68. <a-form-item field="customerProperty.rechargeLimit" :label="$t('customer.rechargeLimit')">
  69. <a-input-number v-model="formData.customerProperty.rechargeLimit" :min="0" :precision="2"
  70. :step="1" :suffix="$t('customer.currencyPerTime')" />
  71. </a-form-item>
  72. <a-form-item field="customerProperty.lineOfCredit" :label="$t('customer.creditLimit')">
  73. <a-input-number v-model="formData.customerProperty.lineOfCredit" :min="0" :precision="2"
  74. :step="100" :suffix="$t('customer.currency')" />
  75. </a-form-item>
  76. <a-form-item field="customerProperty.smsUnitPrice" :label="$t('customer.mobileSmsPrice')">
  77. <a-input-number v-model="formData.customerProperty.smsUnitPrice" :min="0" :precision="2"
  78. :step="0.1" :suffix="$t('customer.currencyPerMessage')" />
  79. </a-form-item>
  80. <a-form-item field="customerProperty.iotSmsUnitPrice" :label="$t('customer.iotSmsPrice')">
  81. <a-input-number v-model="formData.customerProperty.iotSmsUnitPrice" :min="0" :precision="2"
  82. :step="0.1" :suffix="$t('customer.currencyPerMessage')" />
  83. </a-form-item>
  84. <a-form-item field="customerProperty.paymentMethod" :label="$t('customer.paymentMethodName')"
  85. required>
  86. <a-radio-group v-model="formData.customerProperty.paymentMethod">
  87. <a-radio value="prepaid">{{ $t('customer.paymentMethod.prepaid') }}</a-radio>
  88. <a-radio value="postpaid">{{ $t('customer.paymentMethod.postpaid') }}</a-radio>
  89. </a-radio-group>
  90. </a-form-item>
  91. </a-form>
  92. </a-tab-pane>
  93. <a-tab-pane key="3" :title="$t('customer.customerData')">
  94. <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
  95. <a-divider>{{ $t('customer.basicInfoSection') }}</a-divider>
  96. <a-form-item field="customerInfo.platformName" :label="$t('customer.platformName')" required>
  97. <a-input v-model="formData.customerInfo.platformName"
  98. :placeholder="$t('customer.enterPlatformName')" :max-length="60" show-word-limit />
  99. </a-form-item>
  100. <a-form-item field="customerInfo.companyName" :label="$t('customer.companyName')">
  101. <a-input v-model="formData.customerInfo.companyName"
  102. :placeholder="$t('customer.enterCompanyName')" :max-length="60" show-word-limit />
  103. </a-form-item>
  104. <a-form-item field="customerInfo.servicePhone" :label="$t('customer.servicePhone')">
  105. <a-input v-model="formData.customerInfo.servicePhone"
  106. :placeholder="$t('customer.enterServicePhone')" :max-length="60" show-word-limit />
  107. </a-form-item>
  108. <a-form-item field="customerInfo.domain" :label="$t('customer.domain')">
  109. <a-input v-model="formData.customerInfo.domain" :placeholder="$t('customer.enterDomain')"
  110. :max-length="60" show-word-limit />
  111. </a-form-item>
  112. <a-form-item field="customerInfo.homepageLicenseCode" :label="$t('customer.homepageLicenseCode')">
  113. <a-input v-model="formData.customerInfo.homepageLicenseCode"
  114. :placeholder="$t('customer.enterHomepageLicenseCode')" :max-length="60" show-word-limit />
  115. </a-form-item>
  116. <a-form-item field="customerInfo.companyAddress" :label="$t('customer.companyAddress')">
  117. <a-textarea v-model="formData.customerInfo.companyAddress"
  118. :placeholder="$t('customer.enterCompanyAddress')" :max-length="200" show-word-limit />
  119. </a-form-item>
  120. <a-divider>{{ $t('customer.contactPerson') }}</a-divider>
  121. <a-form-item field="customerInfo.contactName" :label="$t('customer.contactName')">
  122. <a-input v-model="formData.customerInfo.contactName"
  123. :placeholder="$t('customer.enterContactName')" :max-length="60" show-word-limit />
  124. </a-form-item>
  125. <a-form-item field="customerInfo.phone" :label="$t('customer.contactPhone')">
  126. <a-input v-model="formData.customerInfo.phone" :placeholder="$t('customer.enterContactPhone')"
  127. :max-length="60" show-word-limit />
  128. </a-form-item>
  129. <a-form-item field="customerInfo.email" :label="$t('customer.contactEmail')">
  130. <a-input v-model="formData.customerInfo.email" :placeholder="$t('customer.enterContactEmail')"
  131. :max-length="60" show-word-limit />
  132. </a-form-item>
  133. <a-form-item field="customerInfo.qq" :label="$t('customer.contactQQ')">
  134. <a-input v-model="formData.customerInfo.qq" :placeholder="$t('customer.enterContactQQ')"
  135. :max-length="60" show-word-limit />
  136. </a-form-item>
  137. <a-divider>{{ $t('customer.deliveryInfo') }}</a-divider>
  138. <a-form-item field="customerInfo.deliveryAddress" :label="$t('customer.deliveryAddress')">
  139. <a-textarea v-model="formData.customerInfo.deliveryAddress"
  140. :placeholder="$t('customer.enterDeliveryAddress')" :max-length="200" show-word-limit />
  141. </a-form-item>
  142. <a-form-item field="customerInfo.deliveryPhone" :label="$t('customer.deliveryPhone')">
  143. <a-input v-model="formData.customerInfo.deliveryPhone"
  144. :placeholder="$t('customer.enterDeliveryPhone')" :max-length="60" show-word-limit />
  145. </a-form-item>
  146. <a-form-item field="customerInfo.deliveryName" :label="$t('customer.deliveryName')">
  147. <a-input v-model="formData.customerInfo.deliveryName"
  148. :placeholder="$t('customer.enterDeliveryName')" :max-length="60" show-word-limit />
  149. </a-form-item>
  150. </a-form>
  151. </a-tab-pane>
  152. <a-tab-pane key="4" :title="$t('customer.interfaceParams')">
  153. <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
  154. <a-divider>{{ $t('customer.basicInfoSection') }}</a-divider>
  155. <a-form-item field="customerInterfaceParams.smsStatusReportUrl"
  156. :label="$t('customer.smsStatusReportUrl')">
  157. <a-input v-model="formData.customerInterfaceParams.smsStatusReportUrl"
  158. :placeholder="$t('customer.enterSmsStatusReportUrl')" :max-length="60" show-word-limit />
  159. </a-form-item>
  160. <a-form-item field="customerInterfaceParams.reportIp" :label="$t('customer.reportIp')">
  161. <a-input v-model="formData.customerInterfaceParams.reportIp"
  162. :placeholder="$t('customer.enterReportIp')" :max-length="60" show-word-limit />
  163. </a-form-item>
  164. <a-form-item field="customerInterfaceParams.deliveryPriority"
  165. :label="$t('customer.deliveryPriorityName')">
  166. <a-select v-model="formData.customerInterfaceParams.deliveryPriority"
  167. :placeholder="$t('customer.selectDeliveryPriority')">
  168. <a-option value="high">{{ $t('customer.deliveryPriority.high') }}</a-option>
  169. <a-option value="medium">{{ $t('customer.deliveryPriority.medium') }}</a-option>
  170. <a-option value="low">{{ $t('customer.deliveryPriority.low') }}</a-option>
  171. </a-select>
  172. </a-form-item>
  173. <a-form-item field="customerInterfaceParams.dataReportUrl" :label="$t('customer.dataReportUrl')">
  174. <a-input v-model="formData.customerInterfaceParams.dataReportUrl"
  175. :placeholder="$t('customer.enterDataReportUrl')" :max-length="60" show-word-limit />
  176. </a-form-item>
  177. </a-form>
  178. </a-tab-pane>
  179. <a-tab-pane key="5" :title="$t('customer.billingInfo')">
  180. <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
  181. <a-form-item field="customerInvoice.invoiceTitle" :label="$t('customer.invoiceTitle')">
  182. <a-input v-model="formData.customerInvoice.invoiceTitle"
  183. :placeholder="$t('customer.enterInvoiceTitle')" :max-length="60" show-word-limit />
  184. </a-form-item>
  185. <a-form-item field="customerInvoice.taxRegistrationNumber"
  186. :label="$t('customer.taxRegistrationNumber')">
  187. <a-input v-model="formData.customerInvoice.taxRegistrationNumber"
  188. :placeholder="$t('customer.enterTaxRegistrationNumber')" :max-length="60" show-word-limit />
  189. </a-form-item>
  190. <a-form-item field="customerInvoice.registeredAddress" :label="$t('customer.registeredAddress')">
  191. <a-input v-model="formData.customerInvoice.registeredAddress"
  192. :placeholder="$t('customer.enterRegisteredAddress')" :max-length="60" show-word-limit />
  193. </a-form-item>
  194. <a-form-item field="customerInvoice.registeredPhone" :label="$t('customer.registeredPhone')">
  195. <a-input v-model="formData.customerInvoice.registeredPhone"
  196. :placeholder="$t('customer.enterRegisteredPhone')" :max-length="60" show-word-limit />
  197. </a-form-item>
  198. <a-form-item field="customerInvoice.bankName" :label="$t('customer.bankName')">
  199. <a-input v-model="formData.customerInvoice.bankName" :placeholder="$t('customer.enterBankName')"
  200. :max-length="60" show-word-limit />
  201. </a-form-item>
  202. <a-form-item field="customerInvoice.bankAccountName" :label="$t('customer.bankAccountName')">
  203. <a-input v-model="formData.customerInvoice.bankAccountName"
  204. :placeholder="$t('customer.enterBankAccountName')" :max-length="60" show-word-limit />
  205. </a-form-item>
  206. <a-form-item field="customerInvoice.bankAccountNumber" :label="$t('customer.bankAccountNumber')">
  207. <a-input v-model="formData.customerInvoice.bankAccountNumber"
  208. :placeholder="$t('customer.enterBankAccountNumber')" :max-length="60" show-word-limit />
  209. </a-form-item>
  210. <a-form-item field="customerInvoice.taxIdentificationNumber"
  211. :label="$t('customer.taxIdentificationNumber')">
  212. <a-input v-model="formData.customerInvoice.taxIdentificationNumber"
  213. :placeholder="$t('customer.enterTaxIdentificationNumber')" :max-length="60"
  214. show-word-limit />
  215. </a-form-item>
  216. <a-form-item field="customerInvoice.invoiceRecipient" :label="$t('customer.invoiceRecipient')">
  217. <a-input v-model="formData.customerInvoice.invoiceRecipient"
  218. :placeholder="$t('customer.enterInvoiceRecipient')" :max-length="60" show-word-limit />
  219. </a-form-item>
  220. <a-form-item field="customerInvoice.recipientPhone" :label="$t('customer.recipientPhone')">
  221. <a-input v-model="formData.customerInvoice.recipientPhone"
  222. :placeholder="$t('customer.enterRecipientPhone')" :max-length="60" show-word-limit />
  223. </a-form-item>
  224. <a-form-item field="customerInvoice.invoiceAddress" :label="$t('customer.invoiceAddress')">
  225. <a-input v-model="formData.customerInvoice.invoiceAddress"
  226. :placeholder="$t('customer.enterInvoiceAddress')" :max-length="60" show-word-limit />
  227. </a-form-item>
  228. <a-form-item field="customerInvoice.invoiceEmail" :label="$t('customer.invoiceEmail')">
  229. <a-input v-model="formData.customerInvoice.invoiceEmail"
  230. :placeholder="$t('customer.enterInvoiceEmail')" :max-length="60" show-word-limit />
  231. </a-form-item>
  232. <a-form-item field="customerInvoice.businessLicenseFile"
  233. :label="$t('customer.businessLicenseFile')">
  234. <a-upload :show-file-list="false"
  235. :custom-request="(option) => handleUpload(option, 'business_license')">
  236. <template #upload-button>
  237. <a-button>{{ $t('customer.uploadFile') }}</a-button>
  238. </template>
  239. </a-upload>
  240. </a-form-item>
  241. <a-form-item field="customerInvoice.taxRegistrationFile"
  242. :label="$t('customer.taxRegistrationFile')">
  243. <a-upload :show-file-list="false"
  244. :custom-request="(option) => handleUpload(option, 'tax_registration')">
  245. <template #upload-button>
  246. <a-button>{{ $t('customer.uploadFile') }}</a-button>
  247. </template>
  248. </a-upload>
  249. </a-form-item>
  250. <a-form-item field="customerInvoice.generalTaxpayerFile"
  251. :label="$t('customer.generalTaxpayerFile')">
  252. <a-upload :show-file-list="false"
  253. :custom-request="(option) => handleUpload(option, 'general_taxpayer')">
  254. <template #upload-button>
  255. <a-button>{{ $t('customer.uploadFile') }}</a-button>
  256. </template>
  257. </a-upload>
  258. </a-form-item>
  259. </a-form>
  260. </a-tab-pane>
  261. <a-tab-pane key="6" :title="$t('customer.purchaseQuality')">
  262. <a-form :model="formData" :label-col-props="{ span: 8 }" :wrapper-col-props="{ span: 16 }">
  263. <template v-for="(field, index) in imageUploadFields" :key="field">
  264. <a-form-item :field="field"
  265. :label="$t(`customer.${field.split('.')[field.split('.').length - 1]}`)">
  266. <a-upload action="/" :file-list="formData[field] ? [formData[field]] : []"
  267. :show-file-list="false" @change="(_, file) => handleFileUpload(field, file)"
  268. @progress="(file) => handleFileProgress(field, file)">
  269. <template #upload-button>
  270. <div :class="`arco-upload-list-item${formData[field] && formData[field].status === 'error' ? ' arco-upload-list-item-error' : ''
  271. }`">
  272. <div class="arco-upload-list-picture custom-upload-avatar"
  273. v-if="formData[field] && formData[field].url">
  274. <img :src="formData[field].url" />
  275. <div class="arco-upload-list-picture-mask">
  276. <icon-edit />
  277. </div>
  278. <a-progress
  279. v-if="formData[field].status === 'uploading' && formData[field].percent < 100"
  280. :percent="formData[field].percent" type="circle" size="mini" :style="{
  281. position: 'absolute',
  282. left: '50%',
  283. top: '50%',
  284. transform: 'translateX(-50%) translateY(-50%)',
  285. }" />
  286. </div>
  287. <div class="arco-upload-picture-card" v-else>
  288. <div class="arco-upload-picture-card-text">
  289. <icon-plus />
  290. <div style="margin-top: 10px; font-weight: 600">{{
  291. $t('customer.uploadFile') }}</div>
  292. </div>
  293. </div>
  294. </div>
  295. </template>
  296. </a-upload>
  297. <div class="upload-description">
  298. {{ $t('customer.imageUploadDescription') }}
  299. </div>
  300. </a-form-item>
  301. </template>
  302. <a-form-item field="customerCardQualification.obtainMethod" :label="$t('customer.obtainMethod')">
  303. <a-upload action="/" :file-list="formData.customerCardQualification.obtainMethod"
  304. @change="handleObtainMethodUpload" multiple>
  305. <template #upload-button>
  306. <a-button>{{ $t('customer.uploadFile') }}</a-button>
  307. </template>
  308. </a-upload>
  309. <div class="upload-description">
  310. {{ $t('customer.obtainMethodDescription') }}
  311. </div>
  312. </a-form-item>
  313. <a-form-item field="customerCardQualification.telephoneApplicationForm"
  314. :label="$t('customer.telephoneApplicationForm')">
  315. <a-upload action="/" :file-list="formData.customerCardQualification.telephoneApplicationForm"
  316. @change="handleTelephoneApplicationFormUpload" multiple>
  317. <template #upload-button>
  318. <a-button>{{ $t('customer.uploadFile') }}</a-button>
  319. </template>
  320. </a-upload>
  321. <div class="upload-description">
  322. {{ $t('customer.telephoneApplicationFormDescription') }}
  323. </div>
  324. </a-form-item>
  325. <a-form-item field="customerCardQualification.otherDocuments"
  326. :label="$t('customer.otherDocuments')">
  327. <a-upload action="/" :file-list="formData.customerCardQualification.otherDocuments"
  328. @change="handleOtherDocumentsUpload" multiple>
  329. <template #upload-button>
  330. <a-button>{{ $t('customer.uploadFile') }}</a-button>
  331. </template>
  332. </a-upload>
  333. <div class="upload-description">
  334. {{ $t('customer.otherDocumentsDescription') }}
  335. </div>
  336. </a-form-item>
  337. </a-form>
  338. </a-tab-pane>
  339. <a-tab-pane key="7" :title="$t('customer.warningNumbers')">
  340. <a-form :model="formData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
  341. <a-form-item field="customerWarningParameter.accountBalanceWarning"
  342. :label="$t('customer.accountBalanceWarning')">
  343. <a-input-number v-model="formData.customerWarningParameter.accountBalanceWarning" :min="0"
  344. :precision="2" :step="100" :style="{ width: '100%' }" />
  345. </a-form-item>
  346. <a-form-item field="customerWarningParameter.reachWarning" :label="$t('customer.reachWarning')">
  347. <a-input-number v-model="formData.customerWarningParameter.reachWarning" :min="0" :max="100"
  348. :precision="0" :step="1" :style="{ width: '100%' }">
  349. <template #append>%</template>
  350. </a-input-number>
  351. </a-form-item>
  352. <a-form-item field="customerWarningParameter.stopSending" :label="$t('customer.stopSending')">
  353. <a-space>
  354. <a-input-number v-model="formData.customerWarningParameter.stopSending" :min="0" :max="100"
  355. :precision="0" :step="1" :style="{ width: '100px' }">
  356. <template #append>%</template>
  357. </a-input-number>
  358. <a-radio-group v-model="formData.customerWarningParameter.stopSendingAction">
  359. <a-radio value="noRecovery">{{ $t('customer.noRecovery') }}</a-radio>
  360. <a-radio value="manualRecovery">{{ $t('customer.manualRecovery') }}</a-radio>
  361. <a-radio value="autoRecovery">{{ $t('customer.autoRecovery') }}</a-radio>
  362. </a-radio-group>
  363. </a-space>
  364. </a-form-item>
  365. <a-form-item field="customerWarningParameter.networkDisconnection"
  366. :label="$t('customer.networkDisconnection')">
  367. <a-space>
  368. <a-input-number v-model="formData.customerWarningParameter.networkDisconnection" :min="0"
  369. :max="100" :precision="0" :step="1" :style="{ width: '100px' }">
  370. <template #append>%</template>
  371. </a-input-number>
  372. <a-radio-group v-model="formData.customerWarningParameter.networkDisconnectionAction">
  373. <a-radio value="noRecovery">{{ $t('customer.noRecovery') }}</a-radio>
  374. <a-radio value="manualRecovery">{{ $t('customer.manualRecovery') }}</a-radio>
  375. <a-radio value="autoRecovery">{{ $t('customer.autoRecovery') }}</a-radio>
  376. </a-radio-group>
  377. </a-space>
  378. </a-form-item>
  379. <a-form-item field="customerWarningParameter.warningPhones" :label="$t('customer.warningPhones')">
  380. <a-input v-model="formData.customerWarningParameter.warningPhones"
  381. :placeholder="$t('customer.enterWarningPhones')" :max-length="60" show-word-limit />
  382. </a-form-item>
  383. <a-form-item field="customerWarningParameter.warningEmails" :label="$t('customer.warningEmails')">
  384. <a-input v-model="formData.customerWarningParameter.warningEmails"
  385. :placeholder="$t('customer.enterWarningEmails')" :max-length="60" show-word-limit />
  386. </a-form-item>
  387. </a-form>
  388. </a-tab-pane>
  389. </a-tabs>
  390. </a-modal>
  391. </template>
  392. <script setup>
  393. import { ref, reactive, watch } from 'vue';
  394. import { Message } from '@arco-design/web-vue';
  395. import { useI18n } from 'vue-i18n';
  396. import { IconEdit, IconPlus } from '@arco-design/web-vue/es/icon';
  397. import dayjs from 'dayjs';
  398. import { useSystemStore } from '@/store/modules/systemStore'
  399. const { t } = useI18n();
  400. const systemStore = useSystemStore()
  401. const props = defineProps({
  402. visible: Boolean,
  403. editMode: Boolean,
  404. editData: Object,
  405. loading: Boolean,
  406. });
  407. watch(
  408. () => props.editData,
  409. (newVal) => {
  410. if (newVal && props.editMode) {
  411. // 深拷贝编辑数据
  412. const editDataCopy = JSON.parse(JSON.stringify(newVal));
  413. // 处理日期格式
  414. if (editDataCopy.customerInfo?.exTime) {
  415. editDataCopy.customerInfo.exTime = dayjs(editDataCopy.customerInfo.exTime).format('YYYY-MM-DD');
  416. }
  417. // 使用 Object.assign 更新每个子对象
  418. Object.keys(formData).forEach(key => {
  419. if (editDataCopy[key]) {
  420. Object.assign(formData[key], editDataCopy[key]);
  421. }
  422. });
  423. }
  424. },
  425. { deep: true, immediate: true }
  426. );
  427. const emit = defineEmits(['update:visible', 'submit']);
  428. const formRef = ref(null);
  429. const formData = reactive({
  430. userInfo: {
  431. username: '',
  432. password: '',
  433. state: '1',
  434. name: '',
  435. id: null
  436. },
  437. customerInfo: {
  438. customerCode: '',
  439. name: '',
  440. platformName: '',
  441. companyName: '',
  442. servicePhone: '',
  443. phone: '',
  444. email: '',
  445. domain: '',
  446. smsName: '',
  447. exTime: null,
  448. remark: '',
  449. homepageLicenseCode: '',
  450. companyAddress: '',
  451. contactName: '',
  452. qq: '',
  453. deliveryAddress: '',
  454. deliveryPhone: '',
  455. deliveryName: '',
  456. smsSubCode: '',
  457. },
  458. customerProperty: {
  459. amount: 0,
  460. rechargeLimit: 0,
  461. lineOfCredit: 0,
  462. smsUnitPrice: 0,
  463. iotSmsUnitPrice: 0,
  464. paymentMethod: 'prepaid',
  465. },
  466. customerInvoice: {
  467. invoiceTitle: '',
  468. taxRegistrationNumber: '',
  469. registeredAddress: '',
  470. registeredPhone: '',
  471. bankName: '',
  472. bankAccountName: '',
  473. bankAccountNumber: '',
  474. taxIdentificationNumber: '',
  475. invoiceRecipient: '',
  476. recipientPhone: '',
  477. invoiceAddress: '',
  478. invoiceEmail: '',
  479. businessLicenseNumber: '',
  480. taxRegistrationFile: '',
  481. businessLicenseFile: '',
  482. generalTaxpayerFile: '',
  483. },
  484. customerCardQualification: {
  485. blImg: null,
  486. legalPersonIdCardImgUp: null,
  487. legalPersonIdCardImgDown: null,
  488. iotImg: null,
  489. contractImg: null,
  490. commitmentImg: null,
  491. customerForm: null,
  492. getCustomerText: '',
  493. phoneForm: null,
  494. otherFile: null,
  495. },
  496. customerWarningParameter: {
  497. accountBalanceWarning: 0,
  498. reachWarning: 0,
  499. stopSending: 0,
  500. stopSendingAction: 'noRecovery',
  501. networkDisconnection: 0,
  502. networkDisconnectionAction: 'noRecovery',
  503. warningPhones: '',
  504. warningEmails: '',
  505. },
  506. customerInterfaceParams: {
  507. smsStatusReportUrl: '',
  508. reportIp: '',
  509. deliveryPriority: '',
  510. dataReportUrl: '',
  511. },
  512. });
  513. const rules = {
  514. 'userInfo.username': [{ required: true, message: t('customer.accountNumberRequired') }],
  515. 'userInfo.password': [{ required: true, message: t('customer.passwordRequired') }],
  516. 'customerInfo.customerCode': [{ required: true, message: t('customer.customerCodeRequired') }],
  517. 'customerInfo.name': [{ required: true, message: t('customer.customerNameRequired') }],
  518. 'customerInfo.exTime': [{ required: true, message: t('customer.validPeriodRequired') }],
  519. 'userInfo.state': [{ required: true, message: t('customer.statusRequired') }],
  520. 'customerInfo.platformName': [{ required: true, message: t('customer.platformNameRequired') }],
  521. 'customerInfo.servicePhone': [{ required: true, message: t('customer.servicePhoneRequired') }],
  522. };
  523. const handleSubmit = () => {
  524. formRef.value.validate((errors) => {
  525. if (!errors) {
  526. // 处理文件字段
  527. const processedInvoice = {
  528. ...formData.customerInvoice,
  529. // 将数组转换为字符串或null
  530. taxRegistrationFile: formData.customerInvoice.taxRegistrationFile?.length ?
  531. formData.customerInvoice.taxRegistrationFile[0]?.url || null : null,
  532. businessLicenseFile: formData.customerInvoice.businessLicenseFile?.length ?
  533. formData.customerInvoice.businessLicenseFile[0]?.url || null : null,
  534. generalTaxpayerFile: formData.customerInvoice.generalTaxpayerFile?.length ?
  535. formData.customerInvoice.generalTaxpayerFile[0]?.url || null : null,
  536. };
  537. const submitData = {
  538. userInfo: {
  539. ...formData.userInfo,
  540. // 设置userInfo.name为customerInfo.name
  541. name: formData.customerInfo.name,
  542. id: props.editMode ? props.editData.userInfo.id : undefined,
  543. },
  544. customerInfo: {
  545. ...formData.customerInfo,
  546. exTime: formData.customerInfo.exTime ?
  547. dayjs(formData.customerInfo.exTime).format('YYYY-MM-DD') :
  548. null
  549. },
  550. customerProperty: formData.customerProperty,
  551. customerInvoice: processedInvoice,
  552. customerCardQualification: formData.customerCardQualification,
  553. customerWarningParameter: formData.customerWarningParameter,
  554. customerInterfaceParams: formData.customerInterfaceParams,
  555. };
  556. emit('submit', submitData);
  557. emit('update:visible', false);
  558. }
  559. });
  560. };
  561. const handleCancel = () => {
  562. emit('update:visible', false);
  563. };
  564. const handleUpload = async (option, directory) => {
  565. const { file } = option.fileItem;
  566. const timestamp = Date.now(); // Get the current timestamp
  567. const fileName = `${directory}/${timestamp}_${file.name}`;
  568. const key = `customer_uploads/${fileName}`; // Base directory for customer uploads
  569. const client = await systemStore.getSTSClient();
  570. const resClient = await client.putObject({
  571. key: key,
  572. body: file
  573. });
  574. if (resClient.statusCode === 200) {
  575. console.log('File uploaded successfully to', key);
  576. formData.customerInvoice[directory + 'File'] = { url: key, name: file.name };
  577. }
  578. };
  579. const generatePassword = () => {
  580. formData.userInfo.password = Math.random().toString(36).slice(-8);
  581. Message.success(t('customer.passwordGenerated'));
  582. };
  583. // 文件上传的处理函数
  584. const handleBusinessLicenseUpload = (fileList) => {
  585. formData.customerInvoice.businessLicenseFile = fileList;
  586. };
  587. const handleTaxRegistrationUpload = (fileList) => {
  588. formData.customerInvoice.taxRegistrationFile = fileList;
  589. };
  590. const handleGeneralTaxpayerUpload = (fileList) => {
  591. formData.customerInvoice.generalTaxpayerFile = fileList;
  592. };
  593. // 文件上传的 action,需要根据实际的后端 API 进行设置
  594. const uploadAction = 'url';
  595. const imageUploadFields = [
  596. 'customerInvoice.businessLicenseFile',
  597. 'customerCardQualification.legalPersonIdCardFrontFile',
  598. 'customerCardQualification.legalPersonIdCardBackFile',
  599. 'customerCardQualification.equipmentPurchaseFile',
  600. 'customerCardQualification.businessContractFile',
  601. 'customerCardQualification.informationSecurityFile',
  602. 'customerCardQualification.customerInformationFile',
  603. ];
  604. const handleFileUpload = (field, file) => {
  605. formData.customerCardQualification[field] = {
  606. ...file,
  607. url: URL.createObjectURL(file.file),
  608. };
  609. };
  610. const handleFileProgress = (field, file) => {
  611. formData.customerCardQualification[field] = file;
  612. };
  613. const handleObtainMethodUpload = (fileList) => {
  614. formData.customerCardQualification.obtainMethod = fileList;
  615. };
  616. const handleTelephoneApplicationFormUpload = (fileList) => {
  617. formData.customerCardQualification.telephoneApplicationForm = fileList;
  618. };
  619. const handleOtherDocumentsUpload = (fileList) => {
  620. formData.customerCardQualification.otherDocuments = fileList;
  621. };
  622. </script>
  623. <style scoped>
  624. .upload-description {
  625. font-size: 12px;
  626. color: #999;
  627. margin-top: 4px;
  628. }
  629. </style>