AddressEdit.mjs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import { withDirectives as _withDirectives, vShow as _vShow, createVNode as _createVNode } from "vue";
  2. import { ref, watch, computed, nextTick, reactive, defineComponent } from "vue";
  3. import { extend, isObject, isMobile, truthProp, numericProp, makeArrayProp, makeNumericProp, createNamespace } from "../utils/index.mjs";
  4. import { useExpose } from "../composables/use-expose.mjs";
  5. import { Area } from "../area/index.mjs";
  6. import { Cell } from "../cell/index.mjs";
  7. import { Form } from "../form/index.mjs";
  8. import { Field } from "../field/index.mjs";
  9. import { Popup } from "../popup/index.mjs";
  10. import { Toast } from "../toast/index.mjs";
  11. import { Button } from "../button/index.mjs";
  12. import { Switch } from "../switch/index.mjs";
  13. import AddressEditDetail from "./AddressEditDetail.mjs";
  14. const [name, bem, t] = createNamespace("address-edit");
  15. const DEFAULT_DATA = {
  16. name: "",
  17. tel: "",
  18. city: "",
  19. county: "",
  20. country: "",
  21. province: "",
  22. areaCode: "",
  23. isDefault: false,
  24. postalCode: "",
  25. addressDetail: ""
  26. };
  27. const isPostal = (value) => /^\d{6}$/.test(value);
  28. const addressEditProps = {
  29. areaList: Object,
  30. isSaving: Boolean,
  31. isDeleting: Boolean,
  32. validator: Function,
  33. showArea: truthProp,
  34. showDetail: truthProp,
  35. showDelete: Boolean,
  36. showPostal: Boolean,
  37. disableArea: Boolean,
  38. searchResult: Array,
  39. telMaxlength: numericProp,
  40. showSetDefault: Boolean,
  41. saveButtonText: String,
  42. areaPlaceholder: String,
  43. deleteButtonText: String,
  44. showSearchResult: Boolean,
  45. detailRows: makeNumericProp(1),
  46. detailMaxlength: makeNumericProp(200),
  47. areaColumnsPlaceholder: makeArrayProp(),
  48. addressInfo: {
  49. type: Object,
  50. default: () => extend({}, DEFAULT_DATA)
  51. },
  52. telValidator: {
  53. type: Function,
  54. default: isMobile
  55. },
  56. postalValidator: {
  57. type: Function,
  58. default: isPostal
  59. }
  60. };
  61. var stdin_default = defineComponent({
  62. name,
  63. props: addressEditProps,
  64. emits: ["save", "focus", "delete", "click-area", "change-area", "change-detail", "select-search", "change-default"],
  65. setup(props, {
  66. emit,
  67. slots
  68. }) {
  69. const areaRef = ref();
  70. const data = reactive({});
  71. const showAreaPopup = ref(false);
  72. const detailFocused = ref(false);
  73. const areaListLoaded = computed(() => isObject(props.areaList) && Object.keys(props.areaList).length);
  74. const areaText = computed(() => {
  75. const {
  76. country,
  77. province,
  78. city,
  79. county,
  80. areaCode
  81. } = data;
  82. if (areaCode) {
  83. const arr = [country, province, city, county];
  84. if (province && province === city) {
  85. arr.splice(1, 1);
  86. }
  87. return arr.filter(Boolean).join("/");
  88. }
  89. return "";
  90. });
  91. const hideBottomFields = computed(() => {
  92. var _a;
  93. return ((_a = props.searchResult) == null ? void 0 : _a.length) && detailFocused.value;
  94. });
  95. const assignAreaValues = () => {
  96. if (areaRef.value) {
  97. const detail = areaRef.value.getArea();
  98. detail.areaCode = detail.code;
  99. delete detail.code;
  100. extend(data, detail);
  101. }
  102. };
  103. const onFocus = (key) => {
  104. detailFocused.value = key === "addressDetail";
  105. emit("focus", key);
  106. };
  107. const rules = computed(() => {
  108. const {
  109. validator,
  110. telValidator,
  111. postalValidator
  112. } = props;
  113. const makeRule = (name2, emptyMessage) => ({
  114. validator: (value) => {
  115. if (validator) {
  116. const message = validator(name2, value);
  117. if (message) {
  118. return message;
  119. }
  120. }
  121. if (!value) {
  122. return emptyMessage;
  123. }
  124. return true;
  125. }
  126. });
  127. return {
  128. name: [makeRule("name", t("nameEmpty"))],
  129. tel: [makeRule("tel", t("telInvalid")), {
  130. validator: telValidator,
  131. message: t("telInvalid")
  132. }],
  133. areaCode: [makeRule("areaCode", t("areaEmpty"))],
  134. addressDetail: [makeRule("addressDetail", t("addressEmpty"))],
  135. postalCode: [makeRule("addressDetail", t("postalEmpty")), {
  136. validator: postalValidator,
  137. message: t("postalEmpty")
  138. }]
  139. };
  140. });
  141. const onSave = () => emit("save", data);
  142. const onChangeDetail = (val) => {
  143. data.addressDetail = val;
  144. emit("change-detail", val);
  145. };
  146. const onAreaConfirm = (values) => {
  147. values = values.filter(Boolean);
  148. if (values.some((value) => !value.code)) {
  149. Toast(t("areaEmpty"));
  150. } else {
  151. showAreaPopup.value = false;
  152. assignAreaValues();
  153. emit("change-area", values);
  154. }
  155. };
  156. const onDelete = () => emit("delete", data);
  157. const getArea = () => {
  158. var _a;
  159. return ((_a = areaRef.value) == null ? void 0 : _a.getValues()) || [];
  160. };
  161. const setAreaCode = (code) => {
  162. data.areaCode = code || "";
  163. if (code) {
  164. nextTick(assignAreaValues);
  165. }
  166. };
  167. const onDetailBlur = () => {
  168. setTimeout(() => {
  169. detailFocused.value = false;
  170. });
  171. };
  172. const setAddressDetail = (value) => {
  173. data.addressDetail = value;
  174. };
  175. const renderSetDefaultCell = () => {
  176. if (props.showSetDefault) {
  177. const slots2 = {
  178. "right-icon": () => _createVNode(Switch, {
  179. "modelValue": data.isDefault,
  180. "onUpdate:modelValue": ($event) => data.isDefault = $event,
  181. "size": "24",
  182. "onChange": (event) => emit("change-default", event)
  183. }, null)
  184. };
  185. return _withDirectives(_createVNode(Cell, {
  186. "center": true,
  187. "title": t("defaultAddress"),
  188. "class": bem("default")
  189. }, slots2), [[_vShow, !hideBottomFields.value]]);
  190. }
  191. };
  192. useExpose({
  193. getArea,
  194. setAreaCode,
  195. setAddressDetail
  196. });
  197. watch(() => props.areaList, () => setAreaCode(data.areaCode));
  198. watch(() => props.addressInfo, (value) => {
  199. extend(data, DEFAULT_DATA, value);
  200. setAreaCode(value.areaCode);
  201. }, {
  202. deep: true,
  203. immediate: true
  204. });
  205. return () => {
  206. const {
  207. disableArea
  208. } = props;
  209. return _createVNode(Form, {
  210. "class": bem(),
  211. "onSubmit": onSave
  212. }, {
  213. default: () => {
  214. var _a;
  215. return [_createVNode("div", {
  216. "class": bem("fields")
  217. }, [_createVNode(Field, {
  218. "modelValue": data.name,
  219. "onUpdate:modelValue": ($event) => data.name = $event,
  220. "clearable": true,
  221. "label": t("name"),
  222. "rules": rules.value.name,
  223. "placeholder": t("name"),
  224. "onFocus": () => onFocus("name")
  225. }, null), _createVNode(Field, {
  226. "modelValue": data.tel,
  227. "onUpdate:modelValue": ($event) => data.tel = $event,
  228. "clearable": true,
  229. "type": "tel",
  230. "label": t("tel"),
  231. "rules": rules.value.tel,
  232. "maxlength": props.telMaxlength,
  233. "placeholder": t("tel"),
  234. "onFocus": () => onFocus("tel")
  235. }, null), _withDirectives(_createVNode(Field, {
  236. "readonly": true,
  237. "label": t("area"),
  238. "is-link": !disableArea,
  239. "modelValue": areaText.value,
  240. "rules": rules.value.areaCode,
  241. "placeholder": props.areaPlaceholder || t("area"),
  242. "onFocus": () => onFocus("areaCode"),
  243. "onClick": () => {
  244. emit("click-area");
  245. showAreaPopup.value = !disableArea;
  246. }
  247. }, null), [[_vShow, props.showArea]]), _createVNode(AddressEditDetail, {
  248. "show": props.showDetail,
  249. "rows": props.detailRows,
  250. "rules": rules.value.addressDetail,
  251. "value": data.addressDetail,
  252. "focused": detailFocused.value,
  253. "maxlength": props.detailMaxlength,
  254. "searchResult": props.searchResult,
  255. "showSearchResult": props.showSearchResult,
  256. "onBlur": onDetailBlur,
  257. "onFocus": () => onFocus("addressDetail"),
  258. "onInput": onChangeDetail,
  259. "onSelect-search": (event) => emit("select-search", event)
  260. }, null), props.showPostal && _withDirectives(_createVNode(Field, {
  261. "modelValue": data.postalCode,
  262. "onUpdate:modelValue": ($event) => data.postalCode = $event,
  263. "type": "tel",
  264. "rules": rules.value.postalCode,
  265. "label": t("postal"),
  266. "maxlength": "6",
  267. "placeholder": t("postal"),
  268. "onFocus": () => onFocus("postalCode")
  269. }, null), [[_vShow, !hideBottomFields.value]]), (_a = slots.default) == null ? void 0 : _a.call(slots)]), renderSetDefaultCell(), _withDirectives(_createVNode("div", {
  270. "class": bem("buttons")
  271. }, [_createVNode(Button, {
  272. "block": true,
  273. "round": true,
  274. "type": "danger",
  275. "text": props.saveButtonText || t("save"),
  276. "class": bem("button"),
  277. "loading": props.isSaving,
  278. "nativeType": "submit"
  279. }, null), props.showDelete && _createVNode(Button, {
  280. "block": true,
  281. "round": true,
  282. "class": bem("button"),
  283. "loading": props.isDeleting,
  284. "text": props.deleteButtonText || t("delete"),
  285. "onClick": onDelete
  286. }, null)]), [[_vShow, !hideBottomFields.value]]), _createVNode(Popup, {
  287. "show": showAreaPopup.value,
  288. "onUpdate:show": ($event) => showAreaPopup.value = $event,
  289. "round": true,
  290. "teleport": "body",
  291. "position": "bottom",
  292. "lazyRender": false
  293. }, {
  294. default: () => [_createVNode(Area, {
  295. "ref": areaRef,
  296. "value": data.areaCode,
  297. "loading": !areaListLoaded.value,
  298. "areaList": props.areaList,
  299. "columnsPlaceholder": props.areaColumnsPlaceholder,
  300. "onConfirm": onAreaConfirm,
  301. "onCancel": () => {
  302. showAreaPopup.value = false;
  303. }
  304. }, null)]
  305. })];
  306. }
  307. });
  308. };
  309. }
  310. });
  311. export {
  312. stdin_default as default
  313. };