index.vue 17 KB

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