123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- <!--element下拉列表封装
- 使用:
- <hyb-select ref="hybSelect"
- url="/v1/orgs"
- v-model="search.orgId" option="orgId" label="orgName"
- placeholder multiple localOptions></hyb-select>
- 1.url:要显示的下拉列表数据来源
- 规范:返回的数据要符合(JSON中对应的字段必须:label和value,不能其他)
- [
- {label:'显示1',value:'值1'},
- {label:'显示2',value:'值2'},
- {label:'显示3',value:'值3'},
- ...
- ]
- 2.v-model数据的双向绑定,绑定父组件中的字段
- 3.option自定义select的value对应的字段
- 4.label自定义select的label对应的字段
- 5.placeholder下拉列表提示
- 6.multiple是否是多选
- 7.localOptions使用本地的数据,不用请求远程数据,注意:使用该属性时Url属性不能要,不然无效
- -->
- <template>
- <div>
- <el-select
- v-model="selectValue"
- :clearable="clearable"
- :allow-create="!!allowCreate"
- :default-first-option="!!allowCreate"
- :collapse-tags="collapseTags"
- filterable
- class="filter-item"
- :placeholder="placeholder"
- :disabled="disabled"
- :multiple="multiple == null ? false : true"
- :remote="remoteFilter"
- :remote-method="remoteQuery"
- @change="change"
- >
- <el-option
- v-for="(item, index) in options"
- :key="index"
- :label="getItemLabel(item, label)"
- :value="item[option] + ''"
- :disabled="isDisabledOption(item)"
- >
- <template v-if="mergeLabel">
- <span style="float: left">{{ getItemLabel(item, label) }}</span>
- <span
- v-if="!dictCode && !localOptions"
- style="float: right; color: #8492a6; font-size: 13px"
- >{{ item[option] }}</span
- >
- </template>
- </el-option>
- <el-option v-if="totalPage >= 1" value="" disabled
- >输入关键词搜索更多</el-option
- >
- </el-select>
- </div>
- </template>
- <script>
- import request from "@/utils/request";
- export default {
- props: {
- dictCode: null, // 当传入dictCode时,可以不用传递url
- url: null,
- allowCreate: {
- type: Boolean,
- default: false
- },
- method: {
- type: String,
- default: "get"
- },
- queryParam: {
- type: Object,
- default: () => {
- return {};
- }
- },
- value: null,
- placeholder: null,
- label: {
- type: String,
- default: "text"
- },
- option: {
- type: String,
- default: "id"
- },
- multiple: null,
- localOptions: null,
- disabled: null,
- clearable: {
- type: Boolean,
- default: true
- },
- collapseTags: {
- type: Boolean,
- default: false
- },
- mergeLabel: {
- type: Boolean,
- default: true
- },
- // 禁用的下拉选项
- disabledOptions: {
- type: String,
- default: () => {
- return "";
- }
- },
- // 使用远程搜索
- remoteFilter: {
- type: Boolean,
- default: false
- }
- },
- data() {
- return {
- options: null,
- selectValue: null,
- // 如果是分页的,
- totalPage: 0
- };
- },
- computed: {
- // 根据dictCode和url拼出最终的请求url
- requestUrl() {
- if (this.localOptions) {
- return null;
- }
- if (this.url != null && this.url.trim() != "") {
- if (this.url.indexOf("?") > 0) {
- if (this.option == null) {
- // console.log('url-' + this.url.substring(this.url.indexOf('?')))
- }
- if (this.label == null) {
- }
- }
- return this.url;
- }
- if (this.dictCode != null && this.dictCode.trim() != "") {
- return `/meta/gaeaDict/select/${this.dictCode}`;
- }
- return null;
- }
- },
- watch: {
- dictCode(val) {
- if (val) {
- this.queryData();
- }
- },
- // 监听接口地址变化时,触发刷新请求
- localOptions(val) {
- this.options = val;
- },
- value: {
- handler(val) {
- if (
- typeof val == "string" &&
- this.url != null &&
- this.url.trim() != ""
- ) {
- this.remoteQuery(val);
- }
- if (this.multiple != null) {
- if (!this.value) {
- this.selectValue = [];
- } else {
- this.selectValue = this.value;
- }
- } else {
- if (this.value != null && this.value != undefined) {
- this.selectValue = this.value + "";
- } else {
- this.selectValue = "";
- }
- }
- },
- immediate: true
- },
- url() {
- setTimeout(() => {
- this.queryData();
- }, 500);
- }
- },
- created() {
- if (this.multiple != null) {
- this.selectValue = this.value;
- } else {
- if (this.value != null) {
- this.selectValue = this.value + "";
- }
- }
- },
- mounted() {
- if (this.requestUrl == null) {
- this.options = this.localOptions;
- return;
- }
- this.queryData();
- },
- methods: {
- // 判断选择是否已经禁用
- isDisabledOption(option) {
- if (
- option == null ||
- this.disabledOptions == null ||
- this.disabledOptions.length == 0
- ) {
- return false;
- }
- let currentOptionVal = option[this.option];
- return this.disabledOptions.indexOf(currentOptionVal) >= 0;
- },
- change(value) {
- if (value === "") {
- value = "";
- }
- this.$emit("input", value);
- // 根据当前值,找出对应的选项
- let optionItem = this.options.find(item => item[this.option] == value);
- this.$emit("change", value, optionItem);
- },
- // 根据用户配置的label,生成对应的标签
- getItemLabel(item, label) {
- if (label.indexOf("${") < 0 && label.indexOf("}" < 0)) {
- return item[label];
- }
- let reg = /\$\{[a-zA-Z0-9]*\}/g;
- let list = label.match(reg);
- // ["${id}", "${text}"]
- let result = label;
- for (let i = 0; i < list.length; i++) {
- let sub = list[i];
- let key = sub.replace("${", "").replace("}", "");
- result = result.replace(sub, item[key]);
- }
- return result;
- },
- // 从本地localStorage取 gaeaDict
- getOptionsFromLocalStorage() {
- let dicts = JSON.parse(localStorage.getItem("gaeaDict"));
- let options = [];
- if (!dicts.hasOwnProperty(this.dictCode)) {
- return [];
- }
- let dictItems = dicts[this.dictCode];
- for (let i = 0; i < dictItems.length; i++) {
- let dictItem = dictItems[i];
- options.push({
- id: dictItem.id.toString(),
- text: dictItem.text,
- extend: dictItem.extend
- });
- }
- return options;
- },
- queryData() {
- // 所有从本地localStorage取,因为在App.vue中已经请求远程保存到本地了
- let options = this.getOptionsFromLocalStorage();
- if (this.isNotBlank(options)) {
- this.options = options;
- return;
- }
- // 本地localStorage取不到,再从远程接口取
- if (this.requestUrl == null) {
- return;
- }
- if (
- this.method != null &&
- this.method.toLocaleLowerCase().trim() == "post"
- ) {
- this.queryDataByPost();
- } else {
- this.queryDataByGet();
- }
- },
- queryDataByGet(keyword) {
- let param = this.deepClone(this.queryParam);
- if (this.isNotBlank(keyword)) {
- param["keyword"] = keyword;
- }
- param["multiple"] = this.multiple == null ? null : 1;
- request({
- url: this.requestUrl,
- headers: { noPrompt: true },
- params: param
- }).then(response => {
- // console.log(response)
- this.setOptions(response.data);
- });
- },
- queryDataByPost(keyword) {
- let param = this.deepClone(this.queryParam);
- if (this.isNotBlank(keyword)) {
- param["keyword"] = keyword;
- }
- request({
- url: this.requestUrl,
- method: "post",
- headers: { noPrompt: true },
- data: param
- }).then(response => {
- this.setOptions(response.data);
- });
- },
- setOptions(resData) {
- if (resData == null || resData.length == 0) {
- this.options = [];
- this.totalPage = 0;
- return;
- }
- if (this.isArray(resData)) {
- this.options = resData;
- this.totalPage = 1;
- return;
- }
- if (
- resData.records == null ||
- resData.total == null ||
- resData.pages == null
- ) {
- this.options = [];
- return;
- }
- this.totalPage = resData.pages;
- // resData.records
- // resData.total
- // resData.size
- // resData.current
- this.options = resData.records;
- },
- remoteQuery(keyword) {
- // if (this.isBlank(keyword)) {
- // return
- // }
- setTimeout(() => {
- if (
- this.method != null &&
- this.method.toLocaleLowerCase().trim() == "post"
- ) {
- this.queryDataByPost(keyword);
- } else {
- this.queryDataByGet(keyword);
- }
- }, 200);
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .el-select {
- width: 100%;
- }
- .el-select-dropdown__item.selected {
- text-align: center;
- }
- .el-select-dropdown__item.is-disabled {
- text-align: center;
- }
- </style>
|