form.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. <template>
  2. <zj-page-layout :hasFooter="true">
  3. <view class="form-container">
  4. <view class="clipboard">
  5. <view class="box">
  6. <u--textarea
  7. v-model="clipboard"
  8. border="none"
  9. placeholder="试试粘贴“收件人姓名,手机号,详细地址”,可快速识别您的用户及地址信息"
  10. ></u--textarea>
  11. <view class="btns">
  12. <u-button text="清空" size="small" @click="clipboard = ''"></u-button>
  13. <u-button type="primary" text="识别" size="small" @click="shibie"></u-button>
  14. </view>
  15. </view>
  16. </view>
  17. <view class="row">
  18. <view class="title">联系人</view>
  19. <view class="right input"><input type="text" placeholder="请输入联系人" v-model="formData.name" /></view>
  20. </view>
  21. <view class="row">
  22. <view class="title">手机号码</view>
  23. <view class="right input"><input type="number" placeholder="请输入手机号码" v-model="formData.phone" /></view>
  24. </view>
  25. <view class="row">
  26. <view class="title">所在地区</view>
  27. <view class="right">
  28. <view class="picker" @tap="selectCity">
  29. <view v-if="formData.province">{{
  30. `${formData.province}/${formData.city}/${formData.area}/${formData.street}`
  31. }}</view>
  32. <view v-else style="color: #666666">请选择省/市/区/街道</view>
  33. <text class="iconfont icon-jinru"></text>
  34. </view>
  35. </view>
  36. </view>
  37. <view class="row">
  38. <view class="title">详细地址</view>
  39. <view class="right textarea">
  40. <textarea placeholder="请输入详细地址" auto-height v-model="formData.address"></textarea>
  41. <view class="r" @tap="getLocation"><text class="iconfont icon-dingwei1"></text>定位</view>
  42. </view>
  43. </view>
  44. <view class="row">
  45. <view class="title">门牌号</view>
  46. <view class="right input"
  47. ><input type="text" placeholder="请输入门牌号" maxlength="15" v-model="formData.houseNo"
  48. /></view>
  49. </view>
  50. <view class="row mt20">
  51. <view class="title">设为默认</view>
  52. <view class="right default"
  53. ><switch
  54. @change="switchChange"
  55. color="#3D8FFD"
  56. v-model="formData.defaultAddr"
  57. :checked="formData.defaultAddr"
  58. style="transform: scale(0.7)"
  59. /></view>
  60. </view>
  61. </view>
  62. <template slot="footer">
  63. <view class="footer-btn-group">
  64. <u-button text="删除" @click="handleDelete" v-if="editId"></u-button>
  65. <u-button text="保存" type="primary" @click="submitForm"></u-button>
  66. </view>
  67. </template>
  68. <city-picker
  69. v-if="isShow"
  70. :isShow="isShow"
  71. :level="4"
  72. :dataList="regionList"
  73. @getCityData="getCityData"
  74. @isClose_city="isClose_city"
  75. @confim_city="confim_city"
  76. ></city-picker>
  77. </zj-page-layout>
  78. </template>
  79. <script>
  80. import { getArea } from '@/common/utils/util.js'
  81. import cityPicker from '@/components/cityPicker.vue'
  82. export default {
  83. components: {
  84. cityPicker
  85. },
  86. data() {
  87. return {
  88. editId: null, // 编辑的id
  89. formData: {
  90. // 表单数据
  91. name: '',
  92. phone: '',
  93. province: '',
  94. city: '',
  95. area: '',
  96. street: '',
  97. address: '',
  98. houseNo: '',
  99. defaultAddr: false
  100. },
  101. canClickSave: true, // 能否点击提交
  102. clipboard: '',
  103. isShow: false,
  104. regionList: []
  105. }
  106. },
  107. onLoad({ id, addressData }) {
  108. this.editId = id
  109. if (id) {
  110. uni.setNavigationBarTitle({
  111. title: '编辑地址'
  112. })
  113. this.getAddressData()
  114. }
  115. if (addressData) {
  116. addressData = JSON.parse(addressData)
  117. this.formData = {
  118. name: addressData.name,
  119. phone: addressData.phone,
  120. province: addressData.province,
  121. city: addressData.city,
  122. area: addressData.area,
  123. address: addressData.address,
  124. houseNo: addressData.houseNo,
  125. defaultAddr: addressData.defaultAddr
  126. }
  127. }
  128. },
  129. methods: {
  130. async getRegionByAddress(address) {
  131. const result = new Promise((resolve, reject) => {
  132. this.$api
  133. .post('/lbs/amap/region/query2', {
  134. address
  135. })
  136. .then(res => {
  137. resolve(res.data)
  138. })
  139. })
  140. return result
  141. },
  142. async getRegionByLatLng(lat, lng) {
  143. const result = new Promise((resolve, reject) => {
  144. this.$api
  145. .post('/lbs/amap/region/query', {
  146. lat,
  147. lng
  148. })
  149. .then(res => {
  150. resolve(res.data)
  151. })
  152. })
  153. return result
  154. },
  155. async shibie() {
  156. // 莫阿宝,13686123158,广东省广州市天河区棠下街道天河软件园
  157. // console.log(this.smart(this.clipboard));
  158. const data = this.smart(this.clipboard)
  159. this.formData.name = data.name || ''
  160. this.formData.phone = data.phone || ''
  161. if (data.address) {
  162. let addressData = await this.getRegionByAddress(data.address)
  163. this.formData.province = addressData.provinceName || ''
  164. this.formData.city = addressData.cityName || ''
  165. this.formData.area = addressData.areaName || ''
  166. this.formData.street = addressData.name || ''
  167. this.formData.address =
  168. data.address.replace(
  169. `${addressData.provinceName || ''}${addressData.cityName || ''}${addressData.areaName || ''}${
  170. addressData.name || ''
  171. }`,
  172. ''
  173. ) || ''
  174. }
  175. },
  176. smart(data) {
  177. data = this.stripscript(data) //过滤特殊字符
  178. let obj = {}
  179. let copyData = JSON.parse(JSON.stringify(data)).split(' ')
  180. copyData.forEach((item, index) => {
  181. if (item) {
  182. let addressObj = this.smartData(item)
  183. console.log(addressObj)
  184. obj = Object.assign(obj, addressObj)
  185. }
  186. })
  187. return obj
  188. },
  189. smartData(data) {
  190. let smartObj = {}
  191. //address= data.replace(/\s/g, ''); //去除空格
  192. // 手机号匹配(提取出手机号)
  193. let phone = data.match(/(86-[1][0-9]{10}) | (86[1][0-9]{10})|([1][0-9]{10})/g)
  194. // 如果存在手机号
  195. if (phone) {
  196. smartObj.phone = phone[0]
  197. if (data != phone[0]) {
  198. // 如果手机号是开头或结尾
  199. if (data.startsWith(phone[0]) || data.endsWith(phone[0])) {
  200. let remainData = data.replace(phone[0], '') // 除了手机号,剩下的内容
  201. // 如果还有剩下的内容
  202. if (remainData) {
  203. if (new RegExp(/省|市|区/).test(remainData)) {
  204. smartObj.address = remainData
  205. } else {
  206. smartObj.name = remainData
  207. }
  208. }
  209. }
  210. // 如果手机号在中间
  211. else {
  212. let remainDatas = data.replace(phone[0], '&&').split('&&') // 除了手机号,剩下的内容
  213. for (let i = 0; i < remainDatas.length; i++) {
  214. if (new RegExp(/省|市|区/).test(remainDatas[i])) {
  215. smartObj.address = remainDatas[i]
  216. } else {
  217. smartObj.name = remainDatas[i]
  218. }
  219. }
  220. }
  221. }
  222. }
  223. // 如果不存在手机号
  224. else {
  225. if (new RegExp(/省|市|区/).test(data)) {
  226. smartObj.address = data
  227. } else {
  228. smartObj.name = data
  229. }
  230. }
  231. return smartObj
  232. },
  233. // 过滤特殊字符
  234. stripscript(s) {
  235. s = s.replace(/(\d{3})-(\d{4})-(\d{4})/g, '$1$2$3')
  236. s = s.replace(/(\d{3}) (\d{4}) (\d{4})/g, '$1$2$3')
  237. var pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“’。,、?-]")
  238. var rs = ''
  239. for (var i = 0; i < s.length; i++) {
  240. rs = rs + s.substr(i, 1).replace(pattern, ' ')
  241. }
  242. rs = rs.replace(/[\r\n]/g, '')
  243. return rs
  244. },
  245. // 获取地址信息
  246. getAddressData() {
  247. this.$api
  248. .get('/user/address/detail', {
  249. userAddressId: this.editId
  250. })
  251. .then(res => {
  252. this.formData = {
  253. name: res.data.name,
  254. phone: res.data.phone,
  255. province: res.data.province,
  256. city: res.data.city,
  257. area: res.data.area,
  258. street: res.data.street,
  259. address: res.data.address,
  260. houseNo: res.data.houseNo,
  261. defaultAddr: res.data.defaultAddr
  262. }
  263. })
  264. },
  265. // 地图选点
  266. getLocation() {
  267. let that = this
  268. uni.chooseLocation({
  269. success: async res => {
  270. console.log(res)
  271. let addressData = await this.getRegionByLatLng(res.latitude, res.longitude)
  272. that.formData.province = addressData.provinceName
  273. that.formData.city = addressData.cityName
  274. that.formData.area = addressData.areaName
  275. that.formData.street = addressData.name
  276. that.formData.address = res.address
  277. that.formData.houseNo = ''
  278. },
  279. fail: function (res) {
  280. uni.getSetting({
  281. success: function (res) {
  282. if (!res.authSetting['scope.userLocation']) {
  283. uni.showModal({
  284. title: '是否授权当前位置',
  285. content: '需要获取您的地理位置,请确认授权,否则地图功能将无法使用',
  286. success(tip) {
  287. if (tip.confirm) {
  288. uni.openSetting({
  289. success: function (data) {
  290. if (data.authSetting['scope.userLocation'] === true) {
  291. that.$successToast('授权成功')
  292. setTimeout(() => {
  293. that.getLocation()
  294. }, 1000)
  295. }
  296. }
  297. })
  298. }
  299. }
  300. })
  301. }
  302. }
  303. })
  304. }
  305. })
  306. },
  307. selectCity() {
  308. this.getCityData('') // 默认广东省
  309. this.isShow = true
  310. },
  311. getCityData(id) {
  312. const that = this
  313. this.$api
  314. .post(
  315. '/common/region',
  316. {
  317. parentId: id
  318. },
  319. false
  320. )
  321. .then(res => {
  322. this.regionList = res.data
  323. })
  324. .catch(() => {})
  325. },
  326. isClose_city(msg) {
  327. this.isShow = msg
  328. },
  329. confim_city(obj) {
  330. console.log(obj)
  331. this.formData.province = obj.province
  332. this.formData.city = obj.city
  333. this.formData.area = obj.area
  334. this.formData.street = obj.street
  335. this.isShow = false
  336. },
  337. switchChange(e) {
  338. this.formData.defaultAddr = e.detail.value
  339. },
  340. // 提交表单
  341. submitForm() {
  342. if (!this.canClickSave) return false
  343. this.canClickSave = false
  344. setTimeout(() => {
  345. this.canClickSave = true
  346. }, 3000)
  347. if (!this.formData.name) {
  348. return this.$toast('请填写姓名')
  349. }
  350. if (!this.formData.phone) {
  351. return this.$toast('请填写手机号码')
  352. }
  353. if (!/^1[3456789]\d{9}$/.test(this.formData.phone) || this.formData.phone.length != 11) {
  354. return this.$toast('请填写正确的手机号码')
  355. }
  356. if (!this.formData.province) {
  357. return this.$toast('请选择所在地区')
  358. }
  359. if (!this.formData.address) {
  360. return this.$toast('请填写详细地址')
  361. }
  362. let params = this.formData
  363. params.userId = this.$store.state.user.userId
  364. let url = ''
  365. if (this.editId) {
  366. params.userAddressId = this.editId
  367. url = '/user/address/update'
  368. } else {
  369. url = '/user/address/save'
  370. }
  371. this.$api
  372. .postJson(url, {
  373. ...params
  374. })
  375. .then(res => {
  376. this.crossPage.$emit('refreshAddressList', res.data)
  377. this.$successToast(this.editId ? '编辑成功' : '添加成功')
  378. this.$navToPage(
  379. {
  380. delta: 1
  381. },
  382. 'navigateBack'
  383. )
  384. })
  385. },
  386. // 删除
  387. handleDelete() {
  388. this.$modal({
  389. content: '确定要删除该地址吗?'
  390. })
  391. .then(() => {
  392. this.$api
  393. .post('/user/address/del', {
  394. userAddressId: this.editId
  395. })
  396. .then(res => {
  397. this.crossPage.$emit('refreshAddressList', false)
  398. this.$successToast('删除成功')
  399. this.$navToPage(
  400. {
  401. delta: 1
  402. },
  403. 'navigateBack'
  404. )
  405. })
  406. })
  407. .catch(() => {})
  408. }
  409. }
  410. }
  411. </script>
  412. <style lang="scss">
  413. .form-container {
  414. .clipboard {
  415. padding: 20rpx;
  416. background: #ffffff;
  417. .box {
  418. background: #f5f5f5;
  419. ::v-deep .u-textarea {
  420. background: none !important;
  421. }
  422. .btns {
  423. padding: 20rpx;
  424. display: flex;
  425. justify-content: flex-end;
  426. ::v-deep .u-button {
  427. width: 100rpx;
  428. margin-left: 30rpx;
  429. margin-right: 0;
  430. }
  431. }
  432. }
  433. }
  434. .row {
  435. background: #ffffff;
  436. min-height: 88rpx;
  437. padding: 0 20rpx;
  438. display: flex;
  439. justify-content: space-between;
  440. align-items: center;
  441. border-bottom: 1px solid #f5f5f5;
  442. .title {
  443. flex-shrink: 0;
  444. width: 160rpx;
  445. font-size: 28rpx;
  446. color: #333333;
  447. }
  448. .right {
  449. flex: 1;
  450. width: 0;
  451. input {
  452. font-size: 28rpx;
  453. }
  454. .picker {
  455. display: flex;
  456. align-items: center;
  457. justify-content: space-between;
  458. view {
  459. font-size: 28rpx;
  460. }
  461. .iconfont {
  462. font-size: 28rpx;
  463. color: $sec-font;
  464. }
  465. }
  466. }
  467. .textarea {
  468. display: flex;
  469. justify-content: space-between;
  470. align-items: center;
  471. textarea {
  472. padding: 16rpx 0;
  473. font-size: 28rpx !important;
  474. }
  475. .r {
  476. display: flex;
  477. align-items: center;
  478. flex-shrink: 0;
  479. font-size: 24rpx;
  480. color: #666666;
  481. margin-left: 15rpx;
  482. .iconfont {
  483. font-size: 36rpx;
  484. color: #999999;
  485. margin-right: 4rpx;
  486. }
  487. }
  488. }
  489. .default {
  490. display: flex;
  491. justify-content: flex-end;
  492. switch {
  493. margin-right: -20rpx;
  494. }
  495. }
  496. }
  497. }
  498. </style>