address.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. <template>
  2. <popup ref="popRef" :title="title" isClose class="address__popup">
  3. <template #content>
  4. <scroll-view class="form" scroll-y>
  5. <view class="form_item">
  6. <view class="item_label">
  7. <trans _t="收件人" />
  8. </view>
  9. <view class="item_value flex">
  10. <Input
  11. :placeholder="t('名')"
  12. border="surround"
  13. @focus="inputFocus"
  14. v-model="form.lastName"
  15. />
  16. <Input
  17. :placeholder="t('姓')"
  18. border="surround"
  19. @focus="inputFocus"
  20. v-model="form.firstName"
  21. />
  22. </view>
  23. </view>
  24. <view class="form_item">
  25. <view class="item_label">
  26. <trans _t="地区" />
  27. </view>
  28. <view class="item_value flex">
  29. <Select
  30. iconColor="#adb8cc"
  31. v-model:current="countryCurrent"
  32. :options="areaList"
  33. keyName="countryName"
  34. isTran
  35. class="country_select"
  36. @select="countryChange"
  37. ref="countryRef"
  38. @selectClick="() => provinceRef.close()"
  39. >
  40. <template #text>
  41. <view
  42. class="select_label"
  43. style="color: var(--inputText)"
  44. v-if="form.country"
  45. >
  46. {{ form.country }}
  47. </view>
  48. <view class="select_label" v-else>
  49. <trans _t="国家" />
  50. </view>
  51. </template>
  52. </Select>
  53. <Select
  54. iconColor="#adb8cc"
  55. v-model:current="provinceCurrent"
  56. :options="provinceList"
  57. keyName="name"
  58. isTran
  59. ref="provinceRef"
  60. class="province_select"
  61. @select="provinceChange"
  62. @selectClick="() => countryRef.close()"
  63. >
  64. <template #text>
  65. <view
  66. class="select_label"
  67. style="color: var(--inputText)"
  68. v-if="form.province"
  69. >
  70. {{ form.province }}
  71. </view>
  72. <view class="select_label" v-else>
  73. <trans _t="选择" />
  74. </view>
  75. </template>
  76. </Select>
  77. <Input border="surround" @focus="inputFocus" v-model="form.city" />
  78. </view>
  79. </view>
  80. <view class="form_item">
  81. <view class="item_label">
  82. <trans _t="详细地址" />
  83. </view>
  84. <view class="item_value">
  85. <Input
  86. :placeholder="t('输入公寓号码街道道路地址')"
  87. @focus="inputFocus"
  88. border="surround"
  89. v-model="form.address"
  90. />
  91. </view>
  92. </view>
  93. <!-- flex -->
  94. <view class="form_item">
  95. <view class="item_label">
  96. <trans _t="门号" />
  97. </view>
  98. <view class="item_value">
  99. <Input
  100. :placeholder="t('如果没有门牌号可以输入')"
  101. @focus="inputFocus"
  102. border="surround"
  103. v-model="form.doorNumber"
  104. />
  105. </view>
  106. </view>
  107. <!-- flex -->
  108. <view class="form_item">
  109. <view class="item_label">
  110. <trans _t="邮政编码" />
  111. </view>
  112. <view class="item_value">
  113. <Input
  114. :placeholder="t('邮政编码')"
  115. border="surround"
  116. @focus="inputFocus"
  117. v-model="form.zipCode"
  118. />
  119. </view>
  120. </view>
  121. <!-- flex -->
  122. <view class="form_item">
  123. <view class="item_label">
  124. <trans _t="电话号码" />
  125. </view>
  126. <view class="item_value">
  127. <Input
  128. :placeholder="t('电话号码')"
  129. border="surround"
  130. @focus="inputFocus"
  131. v-model="form.phoneNo"
  132. />
  133. </view>
  134. </view>
  135. <!-- flex -->
  136. <view class="form_item">
  137. <view class="item_label _required">
  138. <trans _t="税号" />
  139. </view>
  140. <view class="item_value">
  141. <Input
  142. :placeholder="t('税号')"
  143. border="surround"
  144. @focus="inputFocus"
  145. v-model="form.taxId"
  146. />
  147. </view>
  148. </view>
  149. <view class="form_item">
  150. <view class="item_label _required">
  151. <trans _t="地址标签" />
  152. </view>
  153. <view class="item_value">
  154. <Input
  155. :placeholder="t('地址标签')"
  156. border="surround"
  157. @focus="inputFocus"
  158. v-model="form.label"
  159. />
  160. </view>
  161. <view class="labels">
  162. <view
  163. class="labels_item"
  164. :class="form.label == label ? 'labels_active' : ''"
  165. v-for="(label, num) in labels"
  166. :key="num"
  167. @click="form.label = label"
  168. >
  169. <trans :_t="label" />
  170. </view>
  171. </view>
  172. </view>
  173. <view class="form_item flex" style="justify-content: space-between">
  174. <view class="item_label _required">
  175. <trans _t="默认地址" />
  176. </view>
  177. <view class="item_value" style="flex: none">
  178. <up-switch
  179. v-model="form.default"
  180. activeColor="var(--black)"
  181. inactiveColor="#dcdfe6"
  182. ></up-switch>
  183. </view>
  184. </view>
  185. </scroll-view>
  186. </template>
  187. <template #footer>
  188. <view class="submit_btn" @click="submit">
  189. <trans _t="确认" />
  190. </view>
  191. </template>
  192. </popup>
  193. </template>
  194. <script setup>
  195. import { ref, reactive, nextTick } from "vue";
  196. import popup from "./popup";
  197. import Select from "./select";
  198. import areaList from "@/utils/area";
  199. import { t } from "@/locale";
  200. import Input from "./input";
  201. import { Toast } from "@/utils";
  202. import { SHOP_ADDRESS_ADD } from "@/api";
  203. import { useShopStore } from "@/store";
  204. const useShop = useShopStore();
  205. const props = defineProps({
  206. item: {
  207. type: Object,
  208. default: () => ({}),
  209. },
  210. });
  211. const countryRef = ref(null);
  212. const provinceRef = ref(null);
  213. const countryCurrent = ref(0);
  214. const provinceCurrent = ref(0);
  215. const popRef = ref(null);
  216. const title = ref("新增收货地址");
  217. const form = reactive({
  218. id: "",
  219. firstName: "",
  220. lastName: "",
  221. country: "",
  222. province: "",
  223. city: "",
  224. address: "",
  225. doorNumber: "",
  226. zipCode: "",
  227. phoneNo: "",
  228. taxId: "",
  229. label: "",
  230. default: false,
  231. });
  232. const provinceList = ref([]);
  233. const labels = [t("主页"), t("公司")];
  234. const open = (item = {}) => {
  235. popRef.value && popRef.value.open();
  236. form.id = item.id;
  237. form.firstName = item.firstName || "";
  238. form.lastName = item.lastName || "";
  239. form.country = item.country || "";
  240. form.province = item.province || "";
  241. form.city = item.city || "";
  242. form.address = item.address || "";
  243. form.doorNumber = item.doorNumber || "";
  244. form.zipCode = item.zipCode || "";
  245. form.phoneNo = item.phoneNo || "";
  246. form.taxId = item.taxId || "";
  247. form.label = item.label || "";
  248. form.default = item.default ? true : false;
  249. if (JSON.stringify(item) == "{}") {
  250. title.value = "新增收货地址";
  251. } else {
  252. title.value = "编辑收货地址";
  253. const findIndex = areaList.findIndex(
  254. (a) => a.countryName === item.countryName
  255. );
  256. provinceList.value = findIndex == -1 ? [] : areaList[findIndex].regions;
  257. }
  258. };
  259. const close = () => {
  260. popRef.value && popRef.value.close();
  261. };
  262. const countryChange = (item) => {
  263. form.country = item.countryName;
  264. form.province = "";
  265. provinceList.value = item.regions;
  266. provinceRef.value && provinceRef.value.close();
  267. };
  268. const provinceChange = (item) => {
  269. form.province = item.name;
  270. countryRef.value && countryRef.value.close();
  271. };
  272. const inputFocus = () => {
  273. provinceRef.value && provinceRef.value.close();
  274. countryRef.value && countryRef.value.close();
  275. };
  276. const submit = () => {
  277. if (!form.firstName || !form.lastName) return Toast(t("收件人必须填写"));
  278. if (!form.country || !form.province || !form.city)
  279. return Toast(t("国家和州/省必须填写"));
  280. if (!form.address) return Toast(t("详细地址必须填写"));
  281. if (!form.doorNumber) return Toast(t("如果没有门牌号可以输入"));
  282. if (!form.zipCode) return Toast(t("邮政编码必须填写"));
  283. if (!form.phoneNo) return Toast(t("电话号码必须填写"));
  284. addressAdd();
  285. };
  286. const addressAdd = async () => {
  287. try {
  288. const res = await SHOP_ADDRESS_ADD({
  289. ...form,
  290. default: form.default === true ? 1 : 0,
  291. });
  292. nextTick(() => {
  293. useShop.setAddressList();
  294. close();
  295. });
  296. } catch (error) {
  297. Toast(error.msg);
  298. close();
  299. }
  300. };
  301. defineExpose({
  302. open,
  303. close,
  304. });
  305. </script>
  306. <style lang="less" scoped>
  307. @import url("@/style.less");
  308. .form {
  309. &_item {
  310. margin-top: 24rpx;
  311. &:first-child {
  312. margin-top: 0;
  313. }
  314. .item_label {
  315. font-weight: 700;
  316. color: var(--text);
  317. .size(28rpx);
  318. line-height: 60rpx;
  319. white-space: nowrap;
  320. padding-right: 24rpx;
  321. height: 64rpx;
  322. width: fit-content;
  323. position: relative;
  324. &::before {
  325. content: "*";
  326. color: #f56c6c;
  327. margin-right: 8rpx;
  328. }
  329. }
  330. ._required {
  331. &::before {
  332. content: "";
  333. margin-right: 0rpx;
  334. }
  335. }
  336. .item_value {
  337. column-gap: 24rpx;
  338. flex: 1;
  339. /deep/ .u-input {
  340. border-radius: 16rpx;
  341. padding: 0 24rpx !important;
  342. background-color: var(--bg);
  343. .u-input__content {
  344. display: unset;
  345. }
  346. }
  347. /deep/ .u-select {
  348. flex: 1;
  349. height: 32px;
  350. padding: 0 24rpx;
  351. border-radius: 16rpx;
  352. background-color: var(--bg);
  353. border-color: var(--borderColor) !important;
  354. box-shadow: 0 0 0 1px var(--borderColor) inset;
  355. .u-select__label {
  356. margin: 0;
  357. line-height: 32px;
  358. .select_label {
  359. flex: 1;
  360. color: #adb8cc;
  361. .size(28rpx);
  362. .ellipsis();
  363. width: 100%;
  364. }
  365. .u-select__options {
  366. width: 80vw;
  367. }
  368. }
  369. }
  370. .country_select,
  371. .province_select {
  372. /deep/ .u-select__options {
  373. width: 80vw;
  374. .u-select__options_item {
  375. .size(24rpx);
  376. height: 80rpx;
  377. line-height: 80rpx;
  378. padding: 0 64rpx;
  379. .u-select__item_text {
  380. color: var(--inputText);
  381. }
  382. }
  383. .active {
  384. .u-select__item_text {
  385. font-weight: 700;
  386. color: var(--black) !important;
  387. }
  388. }
  389. }
  390. }
  391. .province_select {
  392. /deep/ .u-select__options {
  393. // width: 300rpx;
  394. }
  395. }
  396. }
  397. .labels {
  398. margin-top: 24rpx;
  399. .ver();
  400. gap: 24rpx;
  401. &_item {
  402. border: 1px solid #7d8fb3;
  403. border-radius: 8rpx;
  404. color: #7d8fb3;
  405. padding: 0 28rpx;
  406. line-height: 64rpx;
  407. .size(24rpx);
  408. }
  409. .labels_active {
  410. background-color: var(--black);
  411. border: 1px solid var(--black);
  412. color: var(--light);
  413. }
  414. }
  415. }
  416. }
  417. .submit_btn {
  418. height: 38px;
  419. padding: 16rpx 30rpx;
  420. background-color: var(--black);
  421. color: var(--light);
  422. .flex_center();
  423. border-radius: 16rpx;
  424. .size(24rpx);
  425. }
  426. </style>