AddressEdit.mjs 9.5 KB

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