爱简收旧衣按件回收前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

785 lines
24 KiB

2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <view class="container" :style="{paddingTop: (statusBarHeight + 88) + 'rpx'}">
  3. <!-- 顶部导航 -->
  4. <view class="nav-bar" :style="{height: (statusBarHeight + 88) + 'rpx', paddingTop: statusBarHeight + 'px'}">
  5. <view class="back" @tap="goBack">
  6. <uni-icons type="left" size="20"></uni-icons>
  7. </view>
  8. <text class="title">选择寄件地址</text>
  9. </view>
  10. <!-- 地址列表 -->
  11. <view class="address-list">
  12. <view
  13. class="address-item"
  14. @click="selectAddress(item)"
  15. v-for="(item, index) in addressList"
  16. :key="index"
  17. >
  18. <view class="address-header">
  19. <text class="name">{{item.name}}</text>
  20. <text class="phone">{{item.phone}}</text>
  21. <text v-if="item.defaultFlag === 'Y'" class="default-tag">默认</text>
  22. </view>
  23. <view class="address-text">{{item.address}} {{item.addressDetails}}</view>
  24. <view class="dashed-line"></view>
  25. <view class="address-actions">
  26. <view class="action" @tap="setDefault(item.id)">
  27. <view class="circle" :class="{ active: item.defaultFlag === 'Y' }">
  28. <text v-if="item.defaultFlag === 'Y'" class="check"></text>
  29. </view>
  30. <text :class="{ 'active-text': item.defaultFlag === 'Y' }">默认地址</text>
  31. </view>
  32. <view class="action" @tap="editAddress(item)">
  33. <uni-icons type="compose" size="22" color="#bbb" />
  34. <text>编辑</text>
  35. </view>
  36. <view class="action" @tap="deleteAddress(item.id)">
  37. <uni-icons type="trash" size="22" color="#bbb" />
  38. <text>删除</text>
  39. </view>
  40. </view>
  41. </view>
  42. </view>
  43. <!-- 新建地址按钮 -->
  44. <view class="bottom-bar">
  45. <button class="main-btn" @tap="goToAddAddress">新建地址</button>
  46. </view>
  47. <!-- 遮罩 -->
  48. <view v-if="showAddressModal" class="modal-mask" @tap="closeAddressModal"></view>
  49. <!-- 新建地址弹窗 -->
  50. <view v-if="showAddressModal" class="address-modal">
  51. <view class="modal-header">
  52. <text class="close-btn" @tap="closeAddressModal">关闭</text>
  53. <text class="modal-title">{{form.id ? '编辑地址' : '新建地址'}}</text>
  54. </view>
  55. <view class="modal-form">
  56. <view class="form-item">
  57. <text class="label">联系人</text>
  58. <input class="input" v-model="form.name" placeholder="请输入" />
  59. </view>
  60. <view class="form-item">
  61. <text class="label">手机号</text>
  62. <input class="input" v-model="form.phone" placeholder="请输入" />
  63. </view>
  64. <view class="form-item" @tap="selectAddress">
  65. <text class="label">所在地区</text>
  66. <view class="input region-input">
  67. <text :class="{placeholder: !form.address}">
  68. {{ form.address || '选择省市区街道' }}
  69. </text>
  70. <text class="arrow">></text>
  71. </view>
  72. </view>
  73. <view class="form-item">
  74. <text class="label">详细地址</text>
  75. <input class="input" v-model="form.addressDetails" placeholder="小区楼栋、门牌号、村等" />
  76. </view>
  77. </view>
  78. <button class="main-btn" @tap="saveAddress">保存</button>
  79. </view>
  80. <!-- 地区选择器弹窗 -->
  81. <view v-if="showRegionPicker" class="region-modal">
  82. <view class="modal-header">
  83. <text class="close-btn" @tap="showRegionPicker = false">关闭</text>
  84. <text class="modal-title">手动选择地区</text>
  85. </view>
  86. <view class="region-tip">
  87. <text>请手动选择准确的省市区信息</text>
  88. </view>
  89. <view class="region-picker">
  90. <picker-view style="height:300px;" :value="regionIndex" @change="onRegionChange">
  91. <picker-view-column >
  92. <view v-for="(item,index) in provinces" :key="index" class="item">{{item.name}}</view>
  93. </picker-view-column>
  94. <picker-view-column>
  95. <view v-for="(item,index) in cities" :key="index" class="item">{{item.name}}</view>
  96. </picker-view-column>
  97. <picker-view-column>
  98. <view v-for="(item,index) in districts" :key="index" class="item">{{item.name}}</view>
  99. </picker-view-column>
  100. </picker-view>
  101. </view>
  102. <button class="main-btn" @tap="confirmRegion">确认</button>
  103. </view>
  104. </view>
  105. </template>
  106. <script>
  107. import regionData from '@/pages/subcomponent/region-data.js'
  108. import pullRefreshMixin from '@/pages/mixins/pullRefreshMixin.js'
  109. export default {
  110. mixins: [pullRefreshMixin],
  111. data() {
  112. return {
  113. statusBarHeight: 0,
  114. addressList: [
  115. {
  116. name: '郑文锦',
  117. phone: '18108341643',
  118. address: '海南省海口市秀英区秀英街道5单元183室',
  119. defaultFlag: 'Y'
  120. },
  121. {
  122. name: '周俊',
  123. phone: '13293992217',
  124. address: '贵州省遵义市道真仡佬族苗族自治县洛龙镇5幢172室',
  125. defaultFlag: 'N'
  126. },
  127. {
  128. name: '何炜',
  129. phone: '18108341643',
  130. address: '新疆维吾尔自治区乌鲁木齐市沙依巴克区仓房沟片区街道4单元50室',
  131. defaultFlag: 'N'
  132. },
  133. {
  134. name: '赵晓艳',
  135. phone: '15022123314',
  136. address: '海南省海口市秀英区秀英街道5单元183室',
  137. defaultFlag: 'N'
  138. },
  139. {
  140. name: '冯云',
  141. phone: '15731435825',
  142. address: '甘肃省兰州市城关区滑源路街道13幢199室',
  143. defaultFlag: 'N'
  144. },
  145. {
  146. name: '钱皓皓',
  147. phone: '18734717201',
  148. address: '西藏自治区拉萨市堆龙德庆县东嘎镇7单元94室',
  149. defaultFlag: 'N'
  150. }
  151. ],
  152. batchMode: false,
  153. selectedIndexes: [],
  154. showAddressModal: false,
  155. showRegionPicker: false,
  156. form: {
  157. name: '',
  158. phone: '',
  159. region: [],
  160. address: '',
  161. addressDetails: '',
  162. latitude: '',
  163. longitude: ''
  164. },
  165. provinces: regionData,
  166. cities: [],
  167. districts: [],
  168. regionIndex: [0, 0, 0],
  169. mode: ''
  170. }
  171. },
  172. watch: {
  173. regionIndex: {
  174. handler(val) {
  175. let pIdx = val[0] < this.provinces.length ? val[0] : 0
  176. let cIdx = val[1] < (this.provinces[pIdx]?.children?.length || 0) ? val[1] : 0
  177. this.cities = this.provinces[pIdx]?.children || []
  178. this.districts = this.cities[cIdx]?.children || []
  179. },
  180. immediate: true
  181. }
  182. },
  183. onPullDownRefresh() {
  184. this.getAddressList(() => {
  185. uni.stopPullDownRefresh();
  186. });
  187. },
  188. onLoad(options) {
  189. this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
  190. this.cities = this.provinces[0]?.children || []
  191. this.districts = this.cities[0]?.children || []
  192. this.regionIndex = [0, 0, 0]
  193. this.getAddressList();
  194. this.mode = options.mode || ''
  195. },
  196. methods: {
  197. async onRefresh() {
  198. // 模拟刷新数据
  199. await new Promise(resolve => setTimeout(resolve, 1000))
  200. uni.stopPullRefresh()
  201. },
  202. getAddressList(callback) {
  203. this.$api('getAddressList', {}, res => {
  204. if (res && res.result && res.result.records) {
  205. this.addressList = res.result.records;
  206. }
  207. if (typeof callback === 'function') callback();
  208. });
  209. },
  210. goBack() {
  211. uni.navigateBack()
  212. },
  213. startBatchDelete() {
  214. this.batchMode = true
  215. this.selectedIndexes = []
  216. },
  217. cancelBatchDelete() {
  218. this.batchMode = false
  219. this.selectedIndexes = []
  220. },
  221. selectItem(index) {
  222. if (!this.batchMode) return
  223. const idx = this.selectedIndexes.indexOf(index)
  224. if (idx > -1) {
  225. this.selectedIndexes.splice(idx, 1)
  226. } else {
  227. this.selectedIndexes.push(index)
  228. }
  229. },
  230. confirmDelete() {
  231. if (this.selectedIndexes.length === 0) return
  232. uni.showModal({
  233. title: '提示',
  234. content: '确定要删除选中的地址吗?',
  235. success: (res) => {
  236. if (res.confirm) {
  237. // 从后往前删除,避免索引变化的问题
  238. this.selectedIndexes.sort((a, b) => b - a).forEach(index => {
  239. this.addressList.splice(index, 1)
  240. })
  241. this.batchMode = false
  242. this.selectedIndexes = []
  243. }
  244. }
  245. })
  246. },
  247. editAddress(item) {
  248. this.showAddressModal = true
  249. this.form = {
  250. id: item.id,
  251. name: item.name,
  252. phone: item.phone,
  253. region: [],
  254. address: item.address,
  255. addressDetails: item.addressDetails,
  256. defaultFlag: item.defaultFlag,
  257. latitude: item.latitude || '',
  258. longitude: item.longitude || ''
  259. }
  260. this.regionIndex = [0, 0, 0]
  261. this.cities = this.provinces[0]?.children || []
  262. this.districts = this.cities[0]?.children || []
  263. },
  264. goToAddAddress() {
  265. this.showAddressModal = true
  266. this.form = {
  267. id: undefined,
  268. name: '',
  269. phone: '',
  270. region: [],
  271. address: '',
  272. addressDetails: '',
  273. latitude: '',
  274. longitude: ''
  275. }
  276. this.regionIndex = [0, 0, 0]
  277. this.cities = this.provinces[0]?.children || []
  278. this.districts = this.cities[0]?.children || []
  279. },
  280. selectAddress(address) {
  281. if (this.mode === 'select') {
  282. uni.$emit('addressSelected', {
  283. id: address.id,
  284. name: address.name,
  285. phone: address.phone,
  286. address: address.address,
  287. addressDetails: address.addressDetails
  288. })
  289. uni.navigateBack()
  290. }
  291. },
  292. closeAddressModal() {
  293. this.showAddressModal = false
  294. },
  295. saveAddress() {
  296. if (!this.form.name) return uni.showToast({ title: '请输入联系人', icon: 'none' })
  297. if (!this.form.phone) return uni.showToast({ title: '请输入手机号', icon: 'none' })
  298. if (!this.form.address) return uni.showToast({ title: '请选择地区', icon: 'none' })
  299. if (!this.form.addressDetails) return uni.showToast({ title: '请输入详细地址', icon: 'none' })
  300. // 判断手机号是否合法
  301. if (!/^1[3-9]\d{9}$/.test(this.form.phone)) return uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
  302. const params = {
  303. name: this.form.name,
  304. phone: this.form.phone,
  305. address: this.form.address,
  306. addressDetails: this.form.addressDetails,
  307. defaultFlag: this.form.defaultFlag,
  308. latitude: this.form.latitude,
  309. longitude: this.form.longitude
  310. }
  311. if (this.form.id) params.id = this.form.id
  312. this.$api('saveOrUpdateAddress', params, (res) => {
  313. if(res.code == 200){
  314. uni.showToast({ title: '保存成功', icon: 'success' })
  315. this.closeAddressModal()
  316. // 保存成功后刷新地址列表
  317. this.getAddressList()
  318. }
  319. })
  320. },
  321. onRegionChange(e) {
  322. let [pIdx, cIdx, dIdx] = e.detail.value
  323. if (pIdx !== this.regionIndex[0]) {
  324. cIdx = 0
  325. dIdx = 0
  326. } else if (cIdx !== this.regionIndex[1]) {
  327. dIdx = 0
  328. }
  329. this.regionIndex = [pIdx, cIdx, dIdx]
  330. },
  331. // 选择地区
  332. selectAddress() {
  333. // 首先检查位置权限
  334. uni.getSetting({
  335. success: (res) => {
  336. if (res.authSetting['scope.userLocation'] === false) {
  337. // 用户之前拒绝了位置权限,引导用户去设置
  338. uni.showModal({
  339. title: '位置权限',
  340. content: '需要获取您的位置信息来选择地址,请在设置中开启位置权限',
  341. confirmText: '去设置',
  342. success: (modalRes) => {
  343. if (modalRes.confirm) {
  344. uni.openSetting()
  345. } else {
  346. // 用户拒绝去设置,直接打开区域选择器
  347. this.showRegionPicker = true
  348. }
  349. },
  350. fail: () => {
  351. this.showRegionPicker = true
  352. }
  353. })
  354. return
  355. }
  356. // 调用位置选择
  357. uni.chooseLocation({
  358. success: res => {
  359. console.log(res);
  360. this.form.latitude = res.latitude
  361. this.form.longitude = res.longitude
  362. var reg = /.+?(省|市|自治区|自治州|县|区)/g;
  363. let address = ''
  364. if (!res.address && res.name) { //用户直接选择城市的逻辑
  365. address = res.name
  366. }
  367. if (res.address || res.name) {
  368. address = res.address + res.name
  369. }
  370. if(!address){
  371. return
  372. }
  373. let arr = address.match(reg)
  374. // 判断是否提取到了省市县信息
  375. if (!arr || arr.length < 2) {
  376. // 提取不到完整的省市县信息,打开区域选择器
  377. uni.showToast({
  378. title: '地址信息不完整,请手动选择',
  379. icon: 'none'
  380. })
  381. this.showRegionPicker = true
  382. return
  383. }
  384. const province = arr[0] || ''
  385. const city = arr[1] || ''
  386. const district = arr[2] || ''
  387. let detail = district || city || province || ''
  388. this.form.addressDetails = address.substring(address.indexOf(detail) + detail.length)
  389. this.form.address = `${province}${city}${district}`
  390. // 尝试匹配到region数据中对应的省市区
  391. this.matchRegionData(province, city, district)
  392. },
  393. fail(e) {
  394. console.log("获取位置信息失败!", e)
  395. // 根据错误类型给出不同提示
  396. if (e.errMsg && e.errMsg.includes('auth deny')) {
  397. uni.showModal({
  398. title: '位置权限',
  399. content: '需要获取您的位置信息来选择地址,请允许位置权限',
  400. confirmText: '重新授权',
  401. success: (modalRes) => {
  402. if (modalRes.confirm) {
  403. uni.openSetting()
  404. } else {
  405. this.showRegionPicker = true
  406. }
  407. }
  408. })
  409. } else if (e.errMsg && e.errMsg.includes('cancel')) {
  410. // 用户取消选择位置,直接打开区域选择器
  411. this.showRegionPicker = true
  412. } else {
  413. // 其他错误,提示并打开区域选择器
  414. uni.showToast({
  415. title: '获取位置失败,请手动选择',
  416. icon: 'none'
  417. })
  418. this.showRegionPicker = true
  419. }
  420. }
  421. })
  422. },
  423. fail: () => {
  424. // 获取设置失败,直接打开区域选择器
  425. this.showRegionPicker = true
  426. }
  427. })
  428. },
  429. // 匹配region数据
  430. matchRegionData(provinceName, cityName, districtName) {
  431. // 查找省份
  432. const provinceIndex = this.provinces.findIndex(p =>
  433. provinceName.includes(p.name) || p.name.includes(provinceName.replace(/省|市|自治区|自治州/g, ''))
  434. )
  435. if (provinceIndex === -1) {
  436. this.regionIndex = [0, 0, 0]
  437. return
  438. }
  439. this.cities = this.provinces[provinceIndex]?.children || []
  440. // 查找城市
  441. const cityIndex = this.cities.findIndex(c =>
  442. cityName.includes(c.name) || c.name.includes(cityName.replace(/市|县|区/g, ''))
  443. )
  444. if (cityIndex === -1) {
  445. this.regionIndex = [provinceIndex, 0, 0]
  446. this.districts = this.cities[0]?.children || []
  447. return
  448. }
  449. this.districts = this.cities[cityIndex]?.children || []
  450. // 查找区县
  451. const districtIndex = this.districts.findIndex(d =>
  452. districtName.includes(d.name) || d.name.includes(districtName.replace(/县|区/g, ''))
  453. )
  454. this.regionIndex = [
  455. provinceIndex,
  456. cityIndex,
  457. districtIndex > -1 ? districtIndex : 0
  458. ]
  459. // 更新form.region
  460. this.form.region = [
  461. this.provinces[provinceIndex]?.code || '',
  462. this.cities[cityIndex]?.code || '',
  463. this.districts[districtIndex > -1 ? districtIndex : 0]?.code || ''
  464. ]
  465. },
  466. confirmRegion() {
  467. const province = this.provinces[this.regionIndex[0]]
  468. const city = this.cities[this.regionIndex[1]]
  469. const district = this.districts[this.regionIndex[2]]
  470. this.form.region = [
  471. province?.code || '',
  472. city?.code || '',
  473. district?.code || ''
  474. ]
  475. this.form.address = [
  476. province?.name || '',
  477. city?.name || '',
  478. district?.name || ''
  479. ].filter(Boolean).join(' ')
  480. this.showRegionPicker = false
  481. },
  482. setDefault(id) {
  483. // 找到当前地址项
  484. const address = this.addressList.find(item => item.id === id)
  485. // 如果已经是默认地址,则取消默认
  486. const defaultFlag = address.defaultFlag === 'Y' ? 'N' : 'Y'
  487. this.$api('updateDefaultAddress', {
  488. id: id
  489. }, (res) => {
  490. if(res.code == 200) {
  491. uni.showToast({
  492. title: defaultFlag === 'Y' ? '设置成功' : '已取消默认',
  493. icon: 'success'
  494. })
  495. // 设置成功后刷新地址列表
  496. this.getAddressList()
  497. }
  498. })
  499. },
  500. deleteAddress(id) {
  501. uni.showModal({
  502. title: '提示',
  503. content: '确定要删除该地址吗?',
  504. success: (res) => {
  505. if (res.confirm) {
  506. this.$api('deleteAddress', {id:id}, res => {
  507. if(res.code == 200) {
  508. uni.showToast({
  509. title: '删除成功',
  510. icon: 'success'
  511. })
  512. // 删除成功后刷新地址列表
  513. this.getAddressList()
  514. }
  515. })
  516. }
  517. }
  518. })
  519. },
  520. initRegionPicker() {
  521. if (this.form.region.length > 0) {
  522. const [provinceCode, cityCode, districtCode] = this.form.region
  523. const provinceIndex = this.provinces.findIndex(p => p.code === provinceCode)
  524. if (provinceIndex > -1) {
  525. this.cities = this.provinces[provinceIndex].children || []
  526. if (this.cities.length === 0) {
  527. this.cities = [{ code: '', name: '请选择' }]
  528. }
  529. const cityIndex = this.cities.findIndex(c => c.code === cityCode)
  530. if (cityIndex > -1) {
  531. this.districts = this.cities[cityIndex].children || []
  532. if (this.districts.length === 0) {
  533. this.districts = [{ code: '', name: '请选择' }]
  534. }
  535. const districtIndex = this.districts.findIndex(d => d.code === districtCode)
  536. this.regionIndex = [
  537. provinceIndex,
  538. cityIndex,
  539. districtIndex > -1 ? districtIndex : 0
  540. ]
  541. return
  542. }
  543. }
  544. }
  545. this.cities = this.provinces[0]?.children || []
  546. if (this.cities.length === 0) {
  547. this.cities = [{ code: '', name: '请选择' }]
  548. }
  549. this.districts = this.cities[0]?.children || []
  550. if (this.districts.length === 0) {
  551. this.districts = [{ code: '', name: '请选择' }]
  552. }
  553. this.regionIndex = [0, 0, 0]
  554. }
  555. },
  556. }
  557. </script>
  558. <style lang="scss" scoped>
  559. .container {
  560. min-height: 100vh;
  561. background: #f8f8f8;
  562. padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
  563. }
  564. .nav-bar {
  565. display: flex;
  566. align-items: center;
  567. background: #fff;
  568. padding: 0 30rpx;
  569. position: fixed;
  570. top: 0;
  571. left: 0;
  572. right: 0;
  573. z-index: 999;
  574. .back {
  575. padding: 20rpx;
  576. margin-left: -20rpx;
  577. }
  578. .title {
  579. flex: 1;
  580. text-align: center;
  581. font-size: 34rpx;
  582. font-weight: 500;
  583. color: #222;
  584. }
  585. .right-btns {
  586. display: flex;
  587. align-items: center;
  588. gap: 30rpx;
  589. .more, .target {
  590. font-size: 40rpx;
  591. color: #333;
  592. }
  593. }
  594. }
  595. .address-list {
  596. padding: 32rpx;
  597. margin-top: calc(38rpx + var(--status-bar-height));
  598. height: calc(100vh - 88rpx - var(--status-bar-height) - 140rpx - env(safe-area-inset-bottom));
  599. box-sizing: border-box;
  600. overflow-y: auto;
  601. -webkit-overflow-scrolling: touch;
  602. .address-item {
  603. background: #fff;
  604. border-radius: 24rpx;
  605. margin-bottom: 24rpx;
  606. padding: 32rpx 28rpx 0 28rpx;
  607. box-shadow: 0 4rpx 24rpx rgba(0,0,0,0.04);
  608. .address-header {
  609. display: flex;
  610. align-items: center;
  611. .name { font-size: 32rpx; color: #222; font-weight: 500; margin-right: 20rpx; }
  612. .phone { font-size: 32rpx; color: #222; }
  613. .default-tag {
  614. margin-left: 18rpx;
  615. font-size: 24rpx;
  616. color: #FF9500;
  617. border: 1rpx solid #FF9500;
  618. border-radius: 8rpx;
  619. padding: 2rpx 12rpx;
  620. background: #FFF7E6;
  621. vertical-align: middle;
  622. }
  623. }
  624. .address-text {
  625. font-size: 28rpx;
  626. color: #888;
  627. margin: 16rpx 0 0 0;
  628. line-height: 1.5;
  629. }
  630. .dashed-line {
  631. border-bottom: 1rpx dashed #eee;
  632. margin: 24rpx 0 0 0;
  633. }
  634. .address-actions {
  635. display: flex;
  636. align-items: center;
  637. justify-content: space-around;
  638. padding: 0 0 18rpx 0;
  639. .action {
  640. display: flex;
  641. align-items: center;
  642. margin-right: 48rpx;
  643. .circle {
  644. width: 36rpx; height: 36rpx; border-radius: 50%;
  645. border: 2rpx solid #FF9500; margin-right: 8rpx;
  646. display: flex; align-items: center; justify-content: center;
  647. &.active {
  648. background: #FF9500; border: none;
  649. .check { color: #fff; font-size: 24rpx; }
  650. }
  651. }
  652. text { font-size: 26rpx; color: #bbb; }
  653. .active-text { color: #FF9500; }
  654. }
  655. }
  656. }
  657. }
  658. .bottom-bar {
  659. position: fixed;
  660. left: 0; right: 0; bottom: 0;
  661. background: #fff;
  662. padding: 24rpx 32rpx env(safe-area-inset-bottom);
  663. z-index: 10;
  664. margin-bottom: calc(40rpx );
  665. }
  666. .main-btn {
  667. width: 100%;
  668. height: 90rpx;
  669. background: linear-gradient(90deg, #FFB74D 0%, #FF9500 100%);
  670. color: #fff;
  671. font-size: 32rpx;
  672. border-radius: 45rpx;
  673. font-weight: bold;
  674. margin: 0 auto;
  675. display: flex; align-items: center; justify-content: center;
  676. box-shadow: 0 4rpx 16rpx rgba(255, 149, 0, 0.08);
  677. }
  678. .modal-mask {
  679. position: fixed; left: 0; right: 0; top: 0; bottom: 0;
  680. background: rgba(0,0,0,0.5); z-index: 1000;
  681. }
  682. .address-modal, .region-modal {
  683. position: fixed; left: 0; right: 0; bottom: 0; z-index: 1001;
  684. background: #fff; border-radius: 32rpx 32rpx 0 0;
  685. box-shadow: 0 -4rpx 32rpx rgba(0,0,0,0.08);
  686. padding-bottom: env(safe-area-inset-bottom);
  687. animation: slideUp 0.2s;
  688. }
  689. @keyframes slideUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
  690. .modal-header {
  691. display: flex; align-items: center; justify-content: space-between;
  692. padding: 32rpx 32rpx 0 32rpx;
  693. .close-btn { color: #bbb; font-size: 30rpx; }
  694. .modal-title { flex: 1; text-align: center; font-size: 34rpx; font-weight: bold; color: #222; }
  695. }
  696. .modal-form {
  697. padding: 0 32rpx;
  698. .form-item {
  699. border-bottom: 1rpx solid #f2f2f2;
  700. padding: 28rpx 0 10rpx 0;
  701. .label { color: #222; font-size: 28rpx; margin-bottom: 8rpx; }
  702. .input, .region-input {
  703. width: 100%; font-size: 28rpx; color: #222; background: none; border: none; outline: none;
  704. &.placeholder { color: #ccc; }
  705. }
  706. .region-input { display: flex; align-items: center; justify-content: space-between; }
  707. .arrow { color: #ccc; font-size: 28rpx; margin-left: 10rpx; }
  708. }
  709. }
  710. .region-tip {
  711. padding: 0 32rpx 16rpx 32rpx;
  712. text-align: center;
  713. text {
  714. font-size: 26rpx;
  715. color: #999;
  716. }
  717. }
  718. .region-picker {
  719. padding: 16rpx 0 0 0;
  720. .picker-view {
  721. width: 100%; height: 300rpx; display: flex; justify-content: center; align-items: center;
  722. .active { color: #222; font-weight: bold; }
  723. view { color: #ccc; font-size: 28rpx; text-align: center; }
  724. }
  725. .item {
  726. // line-height: 100upx;
  727. text-align: center;
  728. display: flex;
  729. align-items: center;
  730. justify-content: center;
  731. // height: 100upx;
  732. font-size: 30rpx;
  733. color: #222;
  734. }
  735. }
  736. </style>