index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <template>
  2. <view class="oder_form_wrap">
  3. <u-navbar placeholder :autoBack="true" title="发单表单" @rightClick="handleNavSaveClick">
  4. <view class="u-nav-slot" slot="right">
  5. 保存
  6. </view>
  7. </u-navbar>
  8. <view class="form_wrap">
  9. <u--form labelPosition="left" labelWidth="100" :model="form" :rules="rules" ref="form" class="form_wrap"
  10. :errorType="'toast'">
  11. <u-form-item label="省市区" borderBottom>
  12. <pick-regions :defaultRegion="defaultRegion" @getRegion="handleGetRegion">
  13. <view class="region-picker">
  14. <template v-if="form.province">
  15. <u--input :value="form.province + '/' + form.city + '/' + form.area" placeholder="点击选择"
  16. readonly suffixIcon="arrow-right" suffixIconStyle="color : #c0c4cc"></u--input>
  17. </template>
  18. <template v-else>
  19. <u--input placeholder="点击选择" readonly suffixIcon="arrow-right"
  20. suffixIconStyle="color : #c0c4cc"></u--input>
  21. </template>
  22. </view>
  23. </pick-regions>
  24. </u-form-item>
  25. <u-form-item label="详细地址" prop="address" borderBottom>
  26. <u--textarea v-model="form.address" placeholder="请输入详细地址" count confirmType="done"></u--textarea>
  27. </u-form-item>
  28. <u-form-item label="上门时间" prop="visitTime" borderBottom>
  29. <date-time-picker v-model="form.visitTime" :value-format="'YYYY-MM-DD HH:mm:ss'" :type="'datetime'">
  30. </date-time-picker>
  31. </u-form-item>
  32. <u-form-item label="类型" prop="category" borderBottom>
  33. <ld-select :list="categoryDict" label-key="dictLabel" value-key="dictValue" placeholder="请选择类型"
  34. v-model="form.category" :border="false"></ld-select>
  35. <u-icon slot="right" name="arrow-right"></u-icon>
  36. </u-form-item>
  37. <u-form-item label="物品品牌" prop="brand" borderBottom>
  38. <ld-select :list="brandDict" label-key="dictLabel" value-key="dictValue" placeholder="请选择物品品牌"
  39. v-model="form.brand" :border="false"></ld-select>
  40. <u-icon slot="right" name="arrow-right"></u-icon>
  41. </u-form-item>
  42. <u-form-item label="价格范围" prop="priceRange" borderBottom>
  43. <u--input v-model="form.priceRange" placeholder="请输入价格范围" border="none"></u--input>
  44. </u-form-item>
  45. <u-form-item label="战术选择" prop="tactic" borderBottom>
  46. <ld-select :list="tacticDict" label-key="dictLabel" value-key="dictValue" placeholder="请选择战术"
  47. v-model="form.tactic" :border="false"></ld-select>
  48. <u-icon slot="right" name="arrow-right"></u-icon>
  49. </u-form-item>
  50. <u-form-item label="补充说明" prop="remarks" borderBottom>
  51. <u--textarea v-model="form.remarks" placeholder="请输入补充说明" count confirmType="done"></u--textarea>
  52. </u-form-item>
  53. </u--form>
  54. </view>
  55. <!-- 文件上传区域 -->
  56. <view class="upload_area" v-if="!sendFormId">
  57. <!-- 聊天记录附件 -->
  58. <order-file-upload title="聊天记录附件" orderFileType="1" :file-list="form.chatAttachmentList"
  59. @update:fileList="updateChatFiles" tip-text="上传聊天截图、录音等文件"></order-file-upload>
  60. <!-- 报价附件 -->
  61. <order-file-upload title="报价附件" orderFileType="2" :file-list="form.quoteAttachmentList"
  62. @update:fileList="updateQuoteFiles" tip-text="上传报价附件"></order-file-upload>
  63. <!-- 高清图附件 -->
  64. <order-file-upload title="高清图附件" orderFileType="3" :file-list="form.hdImageAttachmentList"
  65. @update:fileList="updateHdImageFiles" tip-text="上传物品高清图片"></order-file-upload>
  66. <!-- 其他附件 -->
  67. <order-file-upload title="其他附件" orderFileType="4" :file-list="form.otherAttachmentList"
  68. @update:fileList="updateOtherFiles" tip-text="上传其他相关文件"></order-file-upload>
  69. </view>
  70. </view>
  71. </template>
  72. <script>
  73. import orderFileUpload from '@/components/order-file-upload/order-file-upload.vue'
  74. import dateTimePicker from "@/components/dateTimePicker/dateTimePicker.vue"
  75. import ldSelect from "@/components/ld-select/ld-select.vue"
  76. export default {
  77. components: {
  78. orderFileUpload,
  79. dateTimePicker,
  80. ldSelect
  81. },
  82. data() {
  83. return {
  84. defaultRegion: ['广东省', '广州市', '番禺区'],
  85. categoryDict: [],
  86. tacticDict: [],
  87. brandDict: [],
  88. sendFormId : undefined,
  89. form: {
  90. clueId: '',
  91. sendDate: '',
  92. website: '',
  93. item: '',
  94. phone: '',
  95. address: '',
  96. visitTime: '',
  97. remarks: '',
  98. category: '',
  99. brand: '',
  100. priceRange: '',
  101. tactic: '',
  102. // 地区信息
  103. province: '',
  104. city: '',
  105. area: '',
  106. // 附件列表
  107. chatAttachmentList: [], // 聊天记录附件
  108. quoteAttachmentList: [], // 报价附件
  109. hdImageAttachmentList: [], // 高清图附件
  110. otherAttachmentList: [] // 其他附件
  111. },
  112. rules: {
  113. sendDate: {
  114. type: 'string',
  115. required: true,
  116. message: '请输入发单日期',
  117. trigger: ['blur', 'change']
  118. },
  119. website: {
  120. type: 'url',
  121. message: '请输入正确的网址格式',
  122. trigger: ['blur', 'change']
  123. },
  124. item: {
  125. type: 'string',
  126. required: true,
  127. message: '请输入物品描述',
  128. trigger: ['blur', 'change']
  129. },
  130. phone: {
  131. type: 'string',
  132. required: true,
  133. message: '请输入联系电话',
  134. trigger: ['blur', 'change']
  135. },
  136. address: {
  137. type: 'string',
  138. required: true,
  139. message: '请输入详细地址',
  140. trigger: ['blur', 'change']
  141. },
  142. visitTime: {
  143. type: 'string',
  144. required: true,
  145. message: '请输入上门时间',
  146. trigger: ['blur', 'change']
  147. },
  148. category: {
  149. type: 'string',
  150. required: true,
  151. message: '请选择类型',
  152. trigger: ['blur', 'change']
  153. },
  154. brand: {
  155. type: 'string',
  156. required: true,
  157. message: '请选择物品品牌',
  158. trigger: ['blur', 'change']
  159. },
  160. tactic: {
  161. type: 'string',
  162. required: true,
  163. message: '请选择战术',
  164. trigger: ['blur', 'change']
  165. }
  166. }
  167. }
  168. },
  169. methods: {
  170. // 加载表单数据
  171. async loadFormData(sendFormId) {
  172. try {
  173. const res = await uni.$u.api.getClueSendFormVoByOrderId({
  174. id: sendFormId
  175. });
  176. if (res.code === 200) {
  177. this.form = res.data;
  178. }
  179. } catch (error) {
  180. console.error('加载表单数据失败:', error);
  181. uni.$u.toast('加载表单数据失败');
  182. }
  183. },
  184. // 获取地区选择
  185. handleGetRegion(region) {
  186. const [provinceData, cityData, areaData] = region;
  187. this.form.province = provinceData.name;
  188. this.form.city = cityData.name;
  189. this.form.area = areaData.name;
  190. // 只在详细地址为空时自动填充省市区
  191. if (!this.form.address || this.form.address.trim() === '') {
  192. this.form.address = this.form.province + this.form.city + this.form.area;
  193. }
  194. },
  195. // 更新各类附件
  196. updateChatFiles(fileList) {
  197. this.form.chatAttachmentList = fileList;
  198. },
  199. updateQuoteFiles(fileList) {
  200. this.form.quoteAttachmentList = fileList;
  201. },
  202. updateHdImageFiles(fileList) {
  203. this.form.hdImageAttachmentList = fileList;
  204. },
  205. updateOtherFiles(fileList) {
  206. this.form.otherAttachmentList = fileList;
  207. },
  208. // 文件变化处理
  209. handleFileChange(data) {
  210. console.log('文件上传变化:', data);
  211. },
  212. // 获取字典数据
  213. async getDicts() {
  214. try {
  215. const [categoryRes, tacticRes, brandRes] = await Promise.all([
  216. this.$getDicts('crm_form_category'),
  217. this.$getDicts('crm_form_tactic'),
  218. this.$getDicts('crm_form_brand')
  219. ]);
  220. this.categoryDict = categoryRes;
  221. this.tacticDict = tacticRes;
  222. this.brandDict = brandRes;
  223. } catch (error) {
  224. console.error('获取字典数据失败:', error);
  225. }
  226. },
  227. // 处理保存
  228. async handleNavSaveClick() {
  229. try {
  230. // 表单验证
  231. await this.$refs.form.validate();
  232. if (this.form.id) {
  233. const updatedForm = {
  234. id: this.form.id,
  235. item: this.form.item,
  236. phone: this.form.phone,
  237. authenticateUserId: this.form.authenticateUserId,
  238. category: this.form.category,
  239. brand: this.form.brand,
  240. idCard: this.form.idCard,
  241. customName: this.form.customName,
  242. bankCardNumber: this.form.bankCardNumber,
  243. bankName: this.form.bankName,
  244. paymentMethod: this.form.paymentMethod,
  245. visitTime: this.form.visitTime,
  246. remarks: this.form.remarks,
  247. priceRange: this.form.priceRange,
  248. tactic: this.form.tactic
  249. }
  250. await uni.$u.api.updateClueOrderForm(updatedForm);
  251. uni.$emit('updateSendFormSuccess');
  252. uni.$u.toast('发单记录更新成功');
  253. } else {
  254. // 合并所有附件
  255. const allAttachments = [
  256. ...this.form.chatAttachmentList,
  257. ...this.form.quoteAttachmentList,
  258. ...this.form.hdImageAttachmentList,
  259. ...this.form.otherAttachmentList
  260. ];
  261. // 准备提交数据
  262. const submitData = {
  263. ...this.form,
  264. uploadList: allAttachments
  265. };
  266. await uni.$u.api.saveClueOrderForm(submitData);
  267. uni.$u.toast('发单记录添加成功');
  268. }
  269. // 延迟返回
  270. setTimeout(() => {
  271. uni.navigateBack();
  272. }, 1500);
  273. } catch (error) {
  274. console.error('保存失败:', error);
  275. if (error.message) {
  276. uni.$u.toast(error.message);
  277. }
  278. }
  279. }
  280. },
  281. onLoad(option) {
  282. const clueId = option.clueId;
  283. this.sendFormId = option.sendFormId;
  284. this.form.clueId = clueId;
  285. this.getDicts();
  286. if (option.sendFormId) {
  287. this.loadFormData(option.sendFormId);
  288. }
  289. }
  290. }
  291. </script>
  292. <style lang="scss" scoped>
  293. .oder_form_wrap {
  294. background-color: #f5f5f5;
  295. min-height: 100vh;
  296. padding-bottom: 100rpx;
  297. padding-top: 10px;
  298. }
  299. .form_wrap {
  300. background-color: #fff;
  301. border-radius: 16rpx;
  302. overflow: hidden;
  303. }
  304. .upload_area {
  305. padding: 0 20rpx;
  306. margin: 20rpx 0;
  307. }
  308. .bottom_btn {
  309. position: fixed;
  310. bottom: 0;
  311. left: 0;
  312. right: 0;
  313. padding: 20rpx;
  314. background: #fff;
  315. box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
  316. }
  317. .region-picker {
  318. width: 100%;
  319. }
  320. ::v-deep .u-form-item__body {
  321. padding: 20rpx 40rpx;
  322. }
  323. ::v-deep .u-form-item {
  324. border-bottom: 1rpx solid #f5f5f5;
  325. }
  326. ::v-deep .u-form-item:last-child {
  327. border-bottom: none;
  328. }
  329. </style>