Browse Source

feat:地址栏自动填写功能

qianxinyu 4 tháng trước cách đây
mục cha
commit
8a26519969

+ 19 - 0
package.json

@@ -0,0 +1,19 @@
+{
+    "id": "w-select",
+    "name": "下拉选择器,选择框,支持单选、多选、筛选和清空功能,支持vue2和vue3",
+    "displayName": "下拉选择器,选择框,支持单选、多选、筛选和清空功能,支持vue2和vue3",
+    "version": "1.2.3",
+    "description": "用于下拉选择,使用v-model双向绑定值",
+    "keywords": [
+        "下拉选择框",
+        "单选框",
+        "vue2",
+        "vue3"
+    ],
+    "dcloudext": {
+        "category": [
+            "前端组件",
+            "通用组件"
+        ]
+    }
+}

+ 83 - 11
pages/addr/index.vue

@@ -47,7 +47,7 @@
           <view class="form_group">
             <view class="group_title">店铺名称:</view>
             <view class="group_box">
-              <input type="text" class="form_ctrl" placeholder="请输入营业执照全称" maxlength="20" required="" v-model="addrRequest.contact_shop" />
+              <uni-combox v-model="addrRequest.contact_shop" :candidates="searchResults" @input="onSearchInput" @change="onSearchChange" placeholder="请输入营业执照全称"> </uni-combox>
             </view>
           </view>
           <view class="form_group">
@@ -98,6 +98,15 @@
 import { getProvinces, getMyCity, getAreas, getProvincesIndex, getCityIndex, getAreaIndex } from "../../utils/city";
 import Empty from "@/components/Empty/Empty.vue";
 
+// 防抖函数
+function debounce(func, wait) {
+  let timeout;
+  return function (...args) {
+    clearTimeout(timeout);
+    timeout = setTimeout(() => func.apply(this, args), wait);
+  };
+}
+
 export default {
   components: { Empty },
   data() {
@@ -139,6 +148,10 @@ export default {
         { key: 2, label: "连锁" },
         { key: 3, label: "诊所、社康等" },
       ],
+      //获取的默认地址
+      defaultAddr: {},
+      //远程搜索返回的数据
+      searchResults: [],
     };
   },
   onLoad(param) {
@@ -146,6 +159,7 @@ export default {
     this.autoShowForm = param.type == "create" ? true : false;
     // 获取列表
     this.getList();
+    this.get_remark_addr();
   },
   onReady() {
     if (this.autoShowForm) {
@@ -167,6 +181,49 @@ export default {
     this.addrRequest.contact_area = this.cityArray[2][this.cityValue[2]];
   },
   methods: {
+    onSearchInput: debounce(function (inputVal, isSelect) {
+      console.log("搜索关键字:", this.addrRequest.contact_shop);
+      console.log("是否选择:", isSelect);
+      if (isSelect) return;
+      if (this.addrRequest.contact_shop.trim() === "" || this.addrRequest.contact_shop.length < 2) {
+        this.searchResults = [];
+        return;
+      }
+      this.$http.request("api/custom_addr/get_guess_addr", { contact_shop: this.addrRequest.contact_shop }).then((callback) => {
+        // 获取成功
+        if (callback.code == "success") {
+          this.searchResults = callback.data.map((item, index) => ({
+            text: item.contact_shop,
+            value: index,
+            ...item,
+          }));
+        }
+      });
+    }, 300),
+    onSearchChange(event) {
+      if (event.shop_type !== 0) this.addrRequest.shop_type = event.shop_type;
+      this.addrRequest.contact_addr = event.contact_addr;
+      const { contact_province, contact_city, contact_area } = event;
+      const provinces = getProvincesIndex(contact_province);
+      const city = getCityIndex(contact_city, provinces.city, provinces.index);
+      const area = getAreaIndex(contact_area, city.area);
+      this.cityValue = [provinces.index, city.index, area.index];
+      this.cityArray.splice(1, 1, provinces.city);
+      this.cityArray.splice(2, 1, city.area);
+      this.addrRequest.contact_province = contact_province;
+      this.addrRequest.contact_area = contact_area;
+      this.addrRequest.contact_city = contact_city;
+    },
+    //获取get_remark_addr
+    get_remark_addr() {
+      this.$http.request("api/custom_addr/get_remark_addr").then((callback) => {
+        // 获取成功
+        if (callback.code == "success") {
+          // 通知地址变更
+          this.defaultAddr = callback.data;
+        }
+      });
+    },
     // 获取列表
     getList() {
       // 登录提示
@@ -185,16 +242,31 @@ export default {
     openForm(item) {
       if (!item) {
         this.addrRequest.id = 0;
-        this.addrRequest.contact_name = "";
-        this.addrRequest.contact_phone = "";
-        this.addrRequest.contact_shop = "";
-        this.addrRequest.contact_addr = "";
+        this.addrRequest.contact_name = this.defaultAddr.contact_name;
+        this.addrRequest.contact_phone = this.defaultAddr.contact_phone;
+        this.addrRequest.contact_shop = this.defaultAddr.contact_shop;
+        this.addrRequest.contact_addr = this.defaultAddr.contact_addr;
         this.addrRequest.is_default = 0;
-        this.addrRequest.shop_type = 1;
-        this.cityValue = [0, 0, 0];
-        this.addrRequest.contact_province = "请选择";
-        this.addrRequest.contact_city = "请选择";
-        this.addrRequest.contact_area = "请选择";
+        this.addrRequest.shop_type = this.defaultAddr.shop_type == "" ? 1 : this.defaultAddr.shop_type;
+        const { contact_province, contact_city, contact_area } = this.defaultAddr;
+        if (contact_province == "") {
+          this.cityValue = [0, 0, 0];
+          this.addrRequest.contact_province = "请选择";
+          this.addrRequest.contact_city = "请选择";
+          this.addrRequest.contact_area = "请选择";
+        } else {
+          const provinces = getProvincesIndex(contact_province);
+          const city = getCityIndex(contact_city, provinces.city, provinces.index);
+          const area = getAreaIndex(contact_area, city.area);
+          this.cityValue = [provinces.index, city.index, area.index];
+          this.cityArray.splice(1, 1, provinces.city);
+          this.cityArray.splice(2, 1, city.area);
+          this.addrRequest.contact_province = contact_province;
+          this.addrRequest.contact_area = contact_area;
+          this.addrRequest.contact_city = contact_city;
+          if (contact_area == "") this.addrRequest.contact_area = "请选择";
+          if (contact_city == "") this.addrRequest.contact_city = "请选择";
+        }
       } else {
         if (!item.shop_type) item.shop_type = 1;
         const _cloneItem = JSON.parse(JSON.stringify(item));
@@ -441,9 +513,9 @@ export default {
     background: #ffffff;
     .form_group {
       display: block;
-      overflow: hidden;
       line-height: 60rpx;
       padding: 20rpx 35rpx;
+      height: 56rpx;
       .group_title {
         float: left;
         width: 160rpx;

+ 17 - 0
uni_modules/uni-combox/changelog.md

@@ -0,0 +1,17 @@
+## 1.0.2(2024-09-21)
+- 新增 clearAble属性
+## 1.0.1(2021-11-23)
+- 优化 label、label-width 属性
+## 1.0.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-combox](https://uniapp.dcloud.io/component/uniui/uni-combox)
+## 0.1.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.0.6(2021-05-12)
+- 新增 组件示例地址
+## 0.0.5(2021-04-21)
+- 优化 添加依赖 uni-icons, 导入后自动下载依赖
+## 0.0.4(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 0.0.3(2021-02-04)
+- 调整为uni_modules目录规范

+ 285 - 0
uni_modules/uni-combox/components/uni-combox/uni-combox.vue

@@ -0,0 +1,285 @@
+<template>
+  <view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
+    <view v-if="label" class="uni-combox__label" :style="labelStyle">
+      <text>{{ label }}</text>
+    </view>
+    <view class="uni-combox__input-box">
+      <input class="uni-combox__input" type="text" :placeholder="placeholder" placeholder-class="uni-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus" @blur="onBlur" />
+      <uni-icons v-if="!inputVal || !clearAble" :type="showSelector ? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector"> </uni-icons>
+      <uni-icons v-if="inputVal && clearAble" type="clear" size="24" color="#999" @click="clean"> </uni-icons>
+    </view>
+    <view class="uni-combox__selector" v-if="showSelector">
+      <view class="uni-popper__arrow"></view>
+      <scroll-view scroll-y="true" class="uni-combox__selector-scroll">
+        <view class="uni-combox__selector-empty" v-if="candidates.length === 0">
+          <text>{{ emptyTips }}</text>
+        </view>
+        <view class="uni-combox__selector-item" v-for="(item, index) in candidates" :key="index" @click="onSelectorClick(item.text, index)">
+          <view style="width: 100%" class="text-ellipsis">{{ item.text }}</view>
+        </view>
+      </scroll-view>
+    </view>
+  </view>
+</template>
+
+<script>
+/**
+ * Combox 组合输入框
+ * @description 组合输入框一般用于既可以输入也可以选择的场景
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=1261
+ * @property {String} label 左侧文字
+ * @property {String} labelWidth 左侧内容宽度
+ * @property {String} placeholder 输入框占位符
+ * @property {Array} candidates 候选项列表
+ * @property {String} emptyTips 筛选结果为空时显示的文字
+ * @property {String} value 组合框的值
+ */
+export default {
+  name: "uniCombox",
+  emits: ["input", "update:modelValue", "change"],
+  props: {
+    clearAble: {
+      type: Boolean,
+      default: false,
+    },
+    border: {
+      type: Boolean,
+      default: true,
+    },
+    label: {
+      type: String,
+      default: "",
+    },
+    labelWidth: {
+      type: String,
+      default: "auto",
+    },
+    placeholder: {
+      type: String,
+      default: "",
+    },
+    candidates: {
+      type: Array,
+      default() {
+        return [];
+      },
+    },
+    emptyTips: {
+      type: String,
+      default: "无匹配项",
+    },
+    // #ifndef VUE3
+    value: {
+      type: [String, Number],
+      default: "",
+    },
+    // #endif
+    // #ifdef VUE3
+    modelValue: {
+      type: [String, Number],
+      default: "",
+    },
+    // #endif
+  },
+  data() {
+    return {
+      showSelector: false,
+      inputVal: "",
+    };
+  },
+  computed: {
+    labelStyle() {
+      if (this.labelWidth === "auto") {
+        return "";
+      }
+      return `width: ${this.labelWidth}`;
+    },
+    filterCandidates() {
+      return this.candidates.filter((item) => {
+        return item.toString().indexOf(this.inputVal) > -1;
+      });
+    },
+    filterCandidatesLength() {
+      return this.filterCandidates.length;
+    },
+  },
+  watch: {
+    // #ifndef VUE3
+    value: {
+      handler(newVal) {
+        this.inputVal = newVal;
+      },
+      immediate: true,
+    },
+    // #endif
+    // #ifdef VUE3
+    modelValue: {
+      handler(newVal) {
+        this.inputVal = newVal;
+      },
+      immediate: true,
+    },
+    // #endif
+  },
+  methods: {
+    toggleSelector() {
+      this.showSelector = !this.showSelector;
+    },
+    onFocus() {
+      this.showSelector = true;
+    },
+    onBlur() {
+      setTimeout(() => {
+        this.showSelector = false;
+      }, 154);
+    },
+    onSelectorClick(text, index) {
+      this.inputVal = text;
+      this.showSelector = false;
+      this.$emit("input", this.inputVal, true);
+      this.$emit("update:modelValue", this.inputVal);
+      this.$emit("change", this.candidates[index]);
+    },
+    onInput() {
+      setTimeout(() => {
+        this.$emit("input", this.inputVal, false);
+        this.$emit("update:modelValue", this.inputVal);
+      });
+    },
+    onChange(event) {
+      this.$emit("change", this.inputValue);
+    },
+    clean() {
+      this.inputVal = "";
+      this.onInput();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.uni-combox {
+  font-size: 14px;
+  border: 1px solid #dcdfe6;
+  padding: 0rpx 20rpx;
+  position: relative;
+  /* #ifndef APP-NVUE */
+  display: flex;
+  /* #endif */
+  // height: 40px;
+  flex-direction: row;
+  align-items: center;
+  // border-bottom: solid 1px #DDDDDD;
+  height: 56rpx;
+}
+
+.uni-combox__label {
+  font-size: 16px;
+  line-height: 22px;
+  padding-right: 10px;
+  color: #999999;
+}
+
+.uni-combox__input-box {
+  position: relative;
+  /* #ifndef APP-NVUE */
+  display: flex;
+  /* #endif */
+  flex: 1;
+  flex-direction: row;
+  align-items: center;
+}
+
+.uni-combox__input {
+  flex: 1;
+  font-size: 14px;
+  height: 22px;
+  line-height: 22px;
+}
+
+.uni-combox__input-plac {
+  font-size: 14px;
+  color: #999;
+}
+
+.uni-combox__selector {
+  /* #ifndef APP-NVUE */
+  box-sizing: border-box;
+  /* #endif */
+  position: absolute;
+  bottom: calc(100% + 12px);
+  left: 0;
+  width: 100%;
+  background-color: #ffffff;
+  border: 1px solid #ebeef5;
+  border-radius: 6px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  z-index: 1000;
+  padding: 4px 0;
+}
+
+.uni-combox__selector-scroll {
+  /* #ifndef APP-NVUE */
+  max-height: 100px;
+  box-sizing: border-box;
+  /* #endif */
+}
+
+.uni-combox__selector-empty,
+.uni-combox__selector-item {
+  /* #ifndef APP-NVUE */
+  display: flex;
+  cursor: pointer;
+  /* #endif */
+  line-height: 36px;
+  font-size: 14px;
+  text-align: center;
+  // border-bottom: solid 1px #DDDDDD;
+  padding: 0px 10px;
+  background-color: #ffffff;
+}
+
+.uni-combox__selector-item:hover {
+  background-color: #f9f9f9;
+}
+
+.uni-combox__selector-empty:last-child,
+.uni-combox__selector-item:last-child {
+  /* #ifndef APP-NVUE */
+  border-bottom: none;
+  /* #endif */
+}
+
+// picker 弹出层通用的指示小三角
+.uni-popper__arrow,
+.uni-popper__arrow::after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+  border-width: 6px;
+}
+
+.uni-popper__arrow {
+  filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
+  bottom: -6px; /* 将 top 改为 bottom */
+  left: 10%;
+  margin-right: 3px;
+  border-bottom-width: 0; /* 将 border-top-width 改为 border-bottom-width */
+  border-top-color: #ebeef5; /* 将 border-bottom-color 改为 border-top-color */
+}
+
+.uni-popper__arrow::after {
+  content: " ";
+  bottom: 1px; /* 将 top 改为 bottom */
+  margin-left: -6px;
+  border-bottom-width: 0; /* 将 border-top-width 改为 border-bottom-width */
+  border-top-color: #fff; /* 将 border-bottom-color 改为 border-top-color */
+}
+
+.uni-combox__no-border {
+  border: none;
+}
+</style>

+ 88 - 0
uni_modules/uni-combox/package.json

@@ -0,0 +1,88 @@
+{
+  "id": "uni-combox",
+  "displayName": "uni-combox 组合框",
+  "version": "1.0.2",
+  "description": "可以选择也可以输入的表单项 ",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "combox",
+    "组合框",
+    "select"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+"dcloudext": {
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
+  },
+  "uni_modules": {
+    "dependencies": [
+			"uni-scss",
+			"uni-icons"
+		],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y",
+        "alipay": "n"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "n"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 11 - 0
uni_modules/uni-combox/readme.md

@@ -0,0 +1,11 @@
+
+
+## Combox 组合框
+> **组件名:uni-combox**
+> 代码块: `uCombox`
+
+
+组合框组件。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839