AddressEdit.mjs 9.3 KB

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