index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. <template>
  2. <My-shade />
  3. <view class="content">
  4. <view class="title">
  5. 服务信息
  6. </view>
  7. <up-form :model="form" labelWidth="70" ref="uFormRef">
  8. <up-form-item label="服务类型" :required="rules.servicetype[0].required" prop="servicetype">
  9. <up-radio-group v-model="form.servicetype" @change="servicetypeChange">
  10. <up-radio :customStyle="{ marginLeft: '12px' }" v-for="(item) in servertypes" :key="item"
  11. :label="item" :name="item">
  12. </up-radio>
  13. </up-radio-group>
  14. </up-form-item>
  15. <up-form-item label="产品品类" :required="rules.class1[0].required" prop="class1">
  16. <up-radio-group v-model="form.class1">
  17. <up-radio :customStyle="{ marginLeft: '12px' }" v-for="(item) in class1" :key="item.value"
  18. :label="item.value" :name="item.value">
  19. </up-radio>
  20. </up-radio-group>
  21. </up-form-item>
  22. <up-form-item v-if="rules.class2[0].required" label="故障类型" :required="rules.class2[0].required"
  23. prop="class2">
  24. <up-radio-group v-model="form.class2">
  25. <up-radio :customStyle="{ marginLeft: '12px' }" v-for="(item) in class2" :key="item.value"
  26. :label="item.value" :name="item.value">
  27. </up-radio>
  28. </up-radio-group>
  29. </up-form-item>
  30. <view class="title">
  31. 产品信息
  32. </view>
  33. <up-form-item label="序列号" :required="rules.sku[0].required" prop="sku">
  34. <up-input v-model="form.sku" placeholder="序列号" clearable @blur="skuConfirm">
  35. <template #suffix>
  36. <view style="display: flex;align-items: center;">
  37. <view v-if="form.servicetype && form.servicetype != '安装'" class="my-but"
  38. hover-class="navigator-hover" @click="toSelectProduct2">
  39. 选择产品
  40. </view>
  41. <up-icon name="scan" color="#2979ff" size="28" @click="openScan" />
  42. </view>
  43. </template>
  44. </up-input>
  45. </up-form-item>
  46. <up-form-item label="产品名称" prop="itemname" :required="rules.itemname[0].required">
  47. <up-input v-model="form.itemname" disabled placeholder="请输入序列号或选择产品">
  48. <template #suffix>
  49. <view style="display: flex;align-items: center;">
  50. <view class="my-but" hover-class="navigator-hover" @click="toSelectProduct">
  51. 选择产品
  52. </view>
  53. </view>
  54. </template>
  55. </up-input>
  56. </up-form-item>
  57. <up-form-item label="产品编号" prop="itemno">
  58. <up-input v-model="form.itemno" disabled placeholder="请输入序列号或选择产品" />
  59. </up-form-item>
  60. <up-form-item label="产品型号" prop="model">
  61. <up-input v-model="form.model" disabled placeholder="请输入序列号或选择产品" />
  62. </up-form-item>
  63. <up-form-item label="保修卡号" prop="cardno">
  64. <up-input v-model="form.cardno" disabled placeholder="请输入序列号或选择产品" />
  65. </up-form-item>
  66. <view class="title">
  67. 联系人信息
  68. </view>
  69. <up-form-item label="联系人" :required="rules.scenecontact[0].required" prop="scenecontact">
  70. <up-input v-model="form.scenecontact" placeholder="联系人" clearable />
  71. </up-form-item>
  72. <up-form-item label="手机号" :required="rules.scenecontactphonenumber[0].required"
  73. prop="scenecontactphonenumber">
  74. <up-input type="number" v-model="form.scenecontactphonenumber" placeholder="联系人电话" clearable />
  75. </up-form-item>
  76. <up-form-item label="省市县" :required="rules.province[0].required" prop="province">
  77. <My_region @select="changeRegion"> {{ form.province ? [form.province, form.city, form.county].join("-")
  78. : '选择省市县' }}
  79. </My_region>
  80. </up-form-item>
  81. <up-form-item label="详细地址" prop="address" :required="rules.address[0].required">
  82. <up-textarea maxlength="499" v-model="form.address" placeholder="详细地址" autoHeight height="20" />
  83. </up-form-item>
  84. <up-form-item label="" prop="remarks">
  85. <up-textarea v-model="form.remarks" placeholder="如有特殊需求,您可在此处留言" count></up-textarea>
  86. </up-form-item>
  87. </up-form>
  88. <view style="padding-bottom: 50px;width: 350rpx;margin: 40rpx auto 0;" @click="save">
  89. <My-button text="保存" :loading="loading" />
  90. </view>
  91. </view>
  92. <up-popup :show="products.length" @close="closePopup" :customStyle="{
  93. width: '80vw',
  94. }" mode="right">
  95. <scroll-view :safeAreaInsetBottom="false" scroll-y style="width: 100%;height: 100vh;">
  96. <view class="product" v-for="item in products" :key="item.itemid" hover-class="navigator-hover"
  97. @click="changeItem(item)">
  98. <view class="itemname">
  99. {{ item.itemname }}
  100. </view>
  101. <view class="row">
  102. 序列号: {{ item.sku || '--' }}
  103. </view>
  104. <view class="row">
  105. 产品编号: {{ item.itemno || '--' }}
  106. </view>
  107. <view class="row">
  108. 产品型号: {{ item.model || '--' }}
  109. </view>
  110. <view class="row">
  111. 经销商: {{ item.enterprisename || '--' }}
  112. </view>
  113. <view class="row">
  114. 用户信息: {{ item.name || '--' }} {{ item.phonenumber || '--' }}
  115. </view>
  116. </view>
  117. <view style="height: 30px;" />
  118. </scroll-view>
  119. </up-popup>
  120. </template>
  121. <script setup>
  122. import { ref, reactive, getCurrentInstance } from 'vue';
  123. const { $Http } = getCurrentInstance().proxy;
  124. import { onShow } from '@dcloudio/uni-app';
  125. const WuserRecord = uni.getStorageSync('WuserRecord') || {
  126. name: '',
  127. phonenumber: '',
  128. address: "",
  129. province: '',
  130. city: '',
  131. county: '',
  132. sys_enterpriseid: 0,
  133. sa_customersid: 0
  134. };
  135. const uFormRef = ref(null);
  136. const form = reactive({
  137. sa_serviceorderid: 0,
  138. sa_orderid: 0,
  139. servicetype: '', // 服务类型
  140. class1: '', // 产品品类
  141. class2: '', // 故障类型
  142. sku: '', // 序列号
  143. itemid: '', // 产品ID
  144. itemname: '', // 产品名称
  145. itemno: '', // 产品编号
  146. model: '', // 产品型号
  147. cardno: '', // 保修卡号
  148. scenecontact: WuserRecord.name || '', // 联系人
  149. scenecontactphonenumber: WuserRecord.phonenumber || '', // 联系人电话
  150. province: isNaN(WuserRecord.province) ? WuserRecord.province : '', // 省
  151. city: isNaN(WuserRecord.city) ? WuserRecord.city : '', // 市
  152. county: isNaN(WuserRecord.county) ? WuserRecord.county : '', // 县
  153. address: WuserRecord.address || '', // 详细地址
  154. remarks: ''
  155. });
  156. const rules = reactive({
  157. servicetype: [{ required: true, message: '请选择服务类型', trigger: 'change' }],
  158. class1: [{ required: true, message: '请选择产品品类', trigger: 'change' }],
  159. class2: [{ required: false, message: "请选择故障类型", trigger: 'change' }],
  160. sku: [{ required: false, message: '请输入序列号', trigger: 'blur' }],
  161. itemno: [{ required: false, message: '请输入产品编号', trigger: 'blur' }],
  162. itemname: [{ required: true, message: '请选择产品', trigger: 'blur' }],
  163. model: [{ required: false, message: '请输入产品型号', trigger: 'blur' }],
  164. cardno: [{ required: false, message: '请输入保修卡号', trigger: 'blur' }],
  165. province: [{ required: true, message: '请选择省市县', trigger: 'change' }],
  166. address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
  167. scenecontact: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
  168. scenecontactphonenumber: [{ required: true, message: '请输入联系人电话', trigger: 'blur', pattern: /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/, message: '请输入正确的手机号码' }],
  169. });
  170. // 切换服务类型
  171. function servicetypeChange(type) {
  172. rules.class2[0].required = type == '维修';
  173. rules.sku[0].required = type == '安装';
  174. uFormRef.value.setRules(rules);
  175. }
  176. const class1 = ref(''),
  177. servertypes = ref(['安装', '维修', '清洗']),
  178. class2 = ref('');
  179. onShow(() => {
  180. $Http.getClass('servertype').then(res => {
  181. servertypes.value = res.data.map(v => v.value);
  182. if (res.code !== 1) return uni.showToast({ title: res.msg, icon: 'none' });
  183. });
  184. $Http.getClass('prodclass1').then(res => {
  185. class1.value = res.data;
  186. if (res.code !== 1) return uni.showToast({ title: res.msg, icon: 'none' });
  187. });
  188. $Http.getClass('faulttype').then(res => {
  189. class2.value = res.data;
  190. uFormRef.value.setRules(rules);
  191. if (res.code !== 1) return uni.showToast({ title: res.msg, icon: 'none' });
  192. });
  193. });
  194. // 保存
  195. let loading = ref(false);
  196. function save() {
  197. if (querySku.value === false) return uni.showToast({ title: '序列号不正确', icon: 'none' });
  198. if (loading.value) return;
  199. if (confirm) uFormRef.value.validate().then(valid => {
  200. if (valid) wx.showModal({
  201. content: '请确认预约信息正确以便后续服务,是否确认提交?',
  202. title: '提示',
  203. success: ({ confirm }) => {
  204. form.customername = form.scenecontact;
  205. form.customerphonenumber = form.scenecontactphonenumber;
  206. form.name = form.customername;
  207. form.phonenumber = form.scenecontactphonenumber;
  208. form.sa_customersid = WuserRecord.sa_customersid || 0;
  209. form.sys_enterpriseid = WuserRecord.sys_enterpriseid || 0;
  210. let content = {
  211. ...form,
  212. };
  213. loading.value = true;
  214. $Http.basic({
  215. "id": "20230206091403",
  216. content
  217. }).then(res => {
  218. loading.value = false;
  219. console.log("提交申请单", res);
  220. if (res.code !== 1) {
  221. uni.showToast({ title: res.code !== 1 ? res.msg : "保存成功", icon: 'none', mask: res.code == 1 });
  222. } else {
  223. uni.showModal({
  224. showCancel: false,
  225. content: "预约申请已提交,请保持电话畅通,以便后续服务人员联系您!",
  226. success: (success) => {
  227. uni.navigateBack();
  228. },
  229. })
  230. $Http.basic({
  231. id: 20230206101403,
  232. content: {
  233. sa_serviceorderid: res.data.sa_serviceorderid,
  234. backreason: "",
  235. issumbit: 1
  236. }
  237. }).then(res => {
  238. console.log("提交工单", res);
  239. })
  240. }
  241. }).catch(err => {
  242. loading.value = false;
  243. console.error("保存工单失败", err);
  244. uni.showToast({ title: '保存失败,请稍后重试', icon: 'none' });
  245. });
  246. },
  247. })
  248. })
  249. }
  250. function changeRegion(value) {
  251. form.province = value[0];
  252. form.city = value[1];
  253. form.county = value[2];
  254. }
  255. let querySku = ref(true); // SKU是否正确
  256. function skuConfirm() {
  257. if (form.sku) {
  258. ['contact', 'serviceenterprisename', 'cardno', 'itemid', 'itemname', 'itemno', 'model', 'phonenumber', 'unitname', 'spec'].forEach(key => {
  259. form[key] = '';
  260. });
  261. if (form.sku == '') return;
  262. uni.showLoading({
  263. title: '查询中...',
  264. mask: true,
  265. });
  266. $Http.basic({
  267. "id": 2025080813465203,
  268. "content": {
  269. "pageNumber": 1,
  270. "pageSize": 1,
  271. "where": {
  272. sku: form.sku,
  273. }
  274. }
  275. }).then(res => {
  276. console.log("查询sku", res)
  277. uni.hideLoading();
  278. if (res.code !== 1) return uni.showToast({ title: res.msg, icon: 'none' });
  279. if (res.data.length === 0 || res.data[0].sku !== form.sku) {
  280. uni.showToast({ title: '未找到对应的产品信息', icon: 'none' });
  281. querySku.value = false;
  282. return;
  283. }
  284. querySku.value = true;
  285. res.data[0].contact = res.data[0].name;
  286. res.data[0].serviceenterprisename = res.data[0].serviceenterprisename || res.data[0].enterprisename;
  287. ['contact', 'phonenumber', 'serviceenterprisename', 'cardno', 'itemid', 'itemname', 'itemno', 'model', 'unitname', 'spec', 'address', 'province', 'city', 'county', 'sys_enterpriseid'].forEach(key => {
  288. if (['province', 'city', 'county'].includes(key)) {
  289. if (!isNaN(form[key]) && form[key] !== '') {
  290. form[key] = '';
  291. } else {
  292. form[key] = res.data[0][key] || '';
  293. }
  294. } else {
  295. if ('sys_enterpriseid' == key) {
  296. WuserRecord.sys_enterpriseid = res.data[0][key] || 0;
  297. } else {
  298. form[key] = res.data[0][key] || '';
  299. }
  300. }
  301. });
  302. uni.showToast({ title: '已填充表单', icon: 'none' });
  303. })
  304. } else {
  305. form.sku = '';
  306. }
  307. }
  308. let products = ref([]); // 产品列表
  309. function closePopup() {
  310. products.value = [];
  311. }
  312. function changeItem(item) {
  313. item.contact = item.name;
  314. item.serviceenterprisename = item.serviceenterprisename || item.enterprisename;
  315. ['contact', 'serviceenterprisename', 'sku', 'cardno', 'itemid', 'itemname', 'itemno', 'model', 'phonenumber', 'unitname', 'spec', 'sys_enterpriseid'].forEach(key => {
  316. if ('sys_enterpriseid' == key) {
  317. WuserRecord.sys_enterpriseid = item[key] || 0;
  318. } else {
  319. form[key] = item[key] || '';
  320. }
  321. });
  322. uni.showToast({ title: '已填充表单', icon: 'none' });
  323. querySku.value = true;
  324. closePopup();
  325. }
  326. function openScan() {
  327. uni.navigateTo({
  328. url: '/pages/bookingService/getCode'
  329. });
  330. $Http.getCode = (code) => {
  331. form.sku = code || '';
  332. skuConfirm();
  333. uni.navigateBack()
  334. delete $Http.getCode;
  335. }
  336. return
  337. uni.chooseImage({
  338. count: 1,
  339. success: imgRes => {
  340. const imagePath = imgRes.tempFilePaths[0];
  341. const img = new Image();
  342. img.src = imagePath;
  343. img.onload = async () => {
  344. const codeReader = new BrowserMultiFormatReader();
  345. try {
  346. const result = await codeReader.decodeFromImageElement(img);
  347. form.sku = result.text;
  348. skuConfirm();
  349. } catch (err) {
  350. console.log(err)
  351. uni.showToast({ title: '未识别出二维码或条码', icon: 'none' });
  352. }
  353. };
  354. }
  355. });
  356. }
  357. //去选择产品
  358. function toSelectProduct() {
  359. uni.navigateTo({
  360. url: '/pages/select/product'
  361. });
  362. $Http.onSelected = (item) => {
  363. ['contact', 'serviceenterprisename', 'sku', 'cardno', 'itemid', 'itemname', 'itemno', 'model', 'phonenumber', 'unitname', 'spec'].forEach(key => {
  364. form[key] = item[key] || '';
  365. });
  366. uni.navigateBack()
  367. delete $Http.onSelected
  368. }
  369. }
  370. function toSelectProduct2() {
  371. uni.navigateTo({
  372. url: '/pages/select/myProduct'
  373. });
  374. $Http.onSelected = (item) => {
  375. ['contact', 'phonenumber', 'sku', 'serviceenterprisename', 'cardno', 'itemid', 'itemname', 'itemno', 'model', 'unitname', 'spec', 'address', 'province', 'city', 'county', 'sys_enterpriseid'].forEach(key => {
  376. if (['province', 'city', 'county'].includes(key)) {
  377. if (!isNaN(form[key]) && form[key] !== '') {
  378. form[key] = '';
  379. } else {
  380. form[key] = item[key] || '';
  381. }
  382. } else {
  383. if ('sys_enterpriseid' == key) {
  384. WuserRecord.sys_enterpriseid = item[key] || 0;
  385. } else {
  386. form[key] = item[key] || '';
  387. }
  388. }
  389. });
  390. uni.navigateBack()
  391. delete $Http.onSelected
  392. }
  393. }
  394. </script>
  395. <style lang="scss" scoped>
  396. .content {
  397. width: 100vw;
  398. padding: 20px;
  399. box-sizing: border-box;
  400. min-height: 100vh;
  401. background: #fff;
  402. .picker {
  403. width: 100%;
  404. // border-bottom: 1px solid #dadbde;
  405. font-size: 32rpx;
  406. color: #606266;
  407. padding: 9px;
  408. border-radius: 8rpx;
  409. }
  410. .title {
  411. font-size: 34rpx;
  412. color: #4773EE;
  413. margin: 20rpx 0;
  414. font-weight: bold;
  415. }
  416. }
  417. .product {
  418. padding: 20rpx;
  419. background: #fff;
  420. margin: 10rpx 0;
  421. border-radius: 8rpx;
  422. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  423. .itemname {
  424. font-size: 32rpx;
  425. color: #333;
  426. font-weight: bold;
  427. margin-bottom: 10rpx;
  428. }
  429. .row {
  430. font-size: 28rpx;
  431. color: #666;
  432. margin-top: 8rpx;
  433. }
  434. }
  435. .my-but {
  436. line-height: 44rpx;
  437. padding: 0 20rpx;
  438. background: #2979ff;
  439. color: #fff;
  440. border-radius: 8rpx;
  441. margin-right: 10rpx;
  442. font-size: 24rpx;
  443. }
  444. </style>