|
@@ -1,336 +0,0 @@
|
|
|
-<template>
|
|
|
|
|
- <div v-if="showDisplayValue" class="display-value" @click="handleDisplayValueClick">
|
|
|
|
|
- <span>{{displayValue}}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <a-tree-select
|
|
|
|
|
- v-else
|
|
|
|
|
- ref="selectRef"
|
|
|
|
|
- style="min-width: 150px"
|
|
|
|
|
- :defaultOpen="true"
|
|
|
|
|
- :value="valueV"
|
|
|
|
|
- :dropdown-style="dropdownStyle"
|
|
|
|
|
- :notFoundContent="notFoundContent"
|
|
|
|
|
- :tree-data="treeData"
|
|
|
|
|
- :load-data="handleLoadData"
|
|
|
|
|
- :treeDataSimpleMode="true"
|
|
|
|
|
- :placeholder="placeholder"
|
|
|
|
|
- :allow-clear="allowClear"
|
|
|
|
|
- :multiple="multiple"
|
|
|
|
|
- v-bind="customProps"
|
|
|
|
|
- @blur="handleSelectBlur"
|
|
|
|
|
- @update:value="handleChange"
|
|
|
|
|
- />
|
|
|
|
|
-</template>
|
|
|
|
|
-
|
|
|
|
|
-<script lang="ts">
|
|
|
|
|
-import type { SelectProps } from "ant-design-vue";
|
|
|
|
|
-import { defineComponent, type PropType } from "vue";
|
|
|
|
|
-import type { TreeDataItem } from "../IdAsValueTree";
|
|
|
|
|
-
|
|
|
|
|
-export type LoadDataFun = (pid: string|number, level: number) => Promise<TreeDataItem[]>;
|
|
|
|
|
-export type CheckClickableFun = (item: TreeDataItem) => Promise<boolean>;
|
|
|
|
|
-
|
|
|
|
|
-export type GetDiaplayValue = (ref: IdAsValueTreeDropdownInterface) => string;
|
|
|
|
|
-export type GetRef = (ref: IdAsValueTreeDropdownInterface) => void;
|
|
|
|
|
-
|
|
|
|
|
-/**
|
|
|
|
|
- * IdAsValueTreeDropdown 的公共接口
|
|
|
|
|
- */
|
|
|
|
|
-export interface IdAsValueTreeDropdownInterface {
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取某个ID的树(正排列)
|
|
|
|
|
- * @param value 要获取的ID
|
|
|
|
|
- */
|
|
|
|
|
- getTree(value: number) : Array<TreeDataItem>;
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取某个ID的Lablel
|
|
|
|
|
- * @param value 要获取的ID
|
|
|
|
|
- */
|
|
|
|
|
- getLableByValue(value: number) : string;
|
|
|
|
|
- /**
|
|
|
|
|
- * 重新加载数据
|
|
|
|
|
- */
|
|
|
|
|
- reload(): void;
|
|
|
|
|
-}
|
|
|
|
|
-/**
|
|
|
|
|
- * IdAsValueTreeDropdown 的公共接口
|
|
|
|
|
- */
|
|
|
|
|
-export interface IdAsValueTreeDropdownProps {
|
|
|
|
|
- /**
|
|
|
|
|
- * 允许清除
|
|
|
|
|
- */
|
|
|
|
|
- allowClear?: boolean,
|
|
|
|
|
- /**
|
|
|
|
|
- * 多选?
|
|
|
|
|
- */
|
|
|
|
|
- multiple?: boolean,
|
|
|
|
|
- dropdownStyle?: Record<string, unknown>,
|
|
|
|
|
- disabled?: boolean,
|
|
|
|
|
- placeholder?: string,
|
|
|
|
|
- /**
|
|
|
|
|
- * 未找到数据时的文案
|
|
|
|
|
- */
|
|
|
|
|
- notFoundContent?: string,
|
|
|
|
|
- /**
|
|
|
|
|
- * 初始化时加载数据
|
|
|
|
|
- */
|
|
|
|
|
- loadAtStart?: boolean,
|
|
|
|
|
- /**
|
|
|
|
|
- * 加载数据
|
|
|
|
|
- */
|
|
|
|
|
- loadData?: LoadDataFun,
|
|
|
|
|
- /**
|
|
|
|
|
- * 自定义检查条目是否可点击回调
|
|
|
|
|
- */
|
|
|
|
|
- checkClickable?: CheckClickableFun,
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取显示数据回调
|
|
|
|
|
- */
|
|
|
|
|
- getDisplayValue?: GetDiaplayValue,
|
|
|
|
|
- /**
|
|
|
|
|
- * 是否在非激活时显示临时字符串(防止树形数据没有加载,而无法显示当前值)
|
|
|
|
|
- */
|
|
|
|
|
- showDisplayValueBeforeEdit?: boolean,
|
|
|
|
|
- /**
|
|
|
|
|
- * 子数据最大层级
|
|
|
|
|
- */
|
|
|
|
|
- maxLevel?: number,
|
|
|
|
|
- /**
|
|
|
|
|
- * 是否只有最后一级可以点击
|
|
|
|
|
- */
|
|
|
|
|
- onlyLastLevelClickable?: boolean,
|
|
|
|
|
- /**
|
|
|
|
|
- * a-select 其他自定义参数
|
|
|
|
|
- */
|
|
|
|
|
- customProps?: SelectProps,
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/**
|
|
|
|
|
- * 使用数据的ID作为value的下拉框包装
|
|
|
|
|
- */
|
|
|
|
|
-export default defineComponent({
|
|
|
|
|
- name: "IdAsValueTreeDropdown",
|
|
|
|
|
- emits: [
|
|
|
|
|
- 'update:value',
|
|
|
|
|
- 'change',
|
|
|
|
|
- 'blur',
|
|
|
|
|
- ],
|
|
|
|
|
- props: {
|
|
|
|
|
- allowClear: {
|
|
|
|
|
- default: true,
|
|
|
|
|
- type: Boolean
|
|
|
|
|
- },
|
|
|
|
|
- multiple: {
|
|
|
|
|
- default: false,
|
|
|
|
|
- type: Boolean
|
|
|
|
|
- },
|
|
|
|
|
- dropdownStyle: {
|
|
|
|
|
- type: Object,
|
|
|
|
|
- default: () => { return { maxHeight: '400px', overflow: 'auto' } }
|
|
|
|
|
- },
|
|
|
|
|
- disabled: {
|
|
|
|
|
- default: false,
|
|
|
|
|
- type: Boolean
|
|
|
|
|
- },
|
|
|
|
|
- placeholder: {
|
|
|
|
|
- default: '请选择,输入可进行搜索',
|
|
|
|
|
- type: String
|
|
|
|
|
- },
|
|
|
|
|
- notFoundContent: {
|
|
|
|
|
- default: '未找到数据,请换个搜索词再试',
|
|
|
|
|
- type: String
|
|
|
|
|
- },
|
|
|
|
|
- loadAtStart: {
|
|
|
|
|
- default: true,
|
|
|
|
|
- type: Boolean
|
|
|
|
|
- },
|
|
|
|
|
- value: {
|
|
|
|
|
- default: null,
|
|
|
|
|
- },
|
|
|
|
|
- loadData: {
|
|
|
|
|
- type: Function as PropType<LoadDataFun>,
|
|
|
|
|
- default: null,
|
|
|
|
|
- },
|
|
|
|
|
- checkClickable: {
|
|
|
|
|
- type: Function as PropType<CheckClickableFun>,
|
|
|
|
|
- default: null,
|
|
|
|
|
- },
|
|
|
|
|
- getDisplayValue: {
|
|
|
|
|
- type: Function as PropType<GetDiaplayValue>,
|
|
|
|
|
- default: null,
|
|
|
|
|
- },
|
|
|
|
|
- defaultDisplayValue: {
|
|
|
|
|
- type: String,
|
|
|
|
|
- default: '',
|
|
|
|
|
- },
|
|
|
|
|
- showDisplayValueBeforeEdit: {
|
|
|
|
|
- default: false,
|
|
|
|
|
- type: Boolean
|
|
|
|
|
- },
|
|
|
|
|
- maxLevel: {
|
|
|
|
|
- default: 0,
|
|
|
|
|
- type: Number,
|
|
|
|
|
- },
|
|
|
|
|
- onlyLastLevelClickable: {
|
|
|
|
|
- default: false,
|
|
|
|
|
- type: Boolean
|
|
|
|
|
- },
|
|
|
|
|
- /**
|
|
|
|
|
- * a-select 其他自定义参数
|
|
|
|
|
- */
|
|
|
|
|
- customProps: {
|
|
|
|
|
- type: Object as PropType<SelectProps>,
|
|
|
|
|
- default: null,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- computed: {
|
|
|
|
|
- displayValue() : string {
|
|
|
|
|
- if (this.valueV != null && this.valueV != 0 && this.defaultDisplayValue != '')
|
|
|
|
|
- return this.defaultDisplayValue;
|
|
|
|
|
- if (this.getDisplayValue)
|
|
|
|
|
- return (this.getDisplayValue as GetDiaplayValue)(this as IdAsValueTreeDropdownInterface);
|
|
|
|
|
- return '';
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- methods: {
|
|
|
|
|
- handleChange(value: unknown) {
|
|
|
|
|
- this.$nextTick(() => {
|
|
|
|
|
- if(value != this.value) {
|
|
|
|
|
- this.$emit('update:value', value);
|
|
|
|
|
- this.$emit('change', value);
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- },
|
|
|
|
|
- handleLoadData(treeNode: { dataRef: TreeDataItem }) {
|
|
|
|
|
- return new Promise((resolve: (value?: unknown) => void) => {
|
|
|
|
|
- const { id, level } = treeNode.dataRef;
|
|
|
|
|
- this.doLoadData(id, level as number).then(() => resolve()).catch(() => resolve());
|
|
|
|
|
- });
|
|
|
|
|
- },
|
|
|
|
|
- handleDisplayValueClick() {
|
|
|
|
|
- this.showDisplayValue = false;
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- (this.$refs.selectRef as {
|
|
|
|
|
- focus: () => void
|
|
|
|
|
- }).focus();
|
|
|
|
|
- }, 200);
|
|
|
|
|
- },
|
|
|
|
|
- handleSelectBlur() {
|
|
|
|
|
- if(this.showDisplayValueBeforeEdit) {
|
|
|
|
|
- if(this.valueV != null && this.valueV != 0 && this.defaultDisplayValue != '')
|
|
|
|
|
- this.showDisplayValue = true;
|
|
|
|
|
- else if (this.getLableByValue(this.valueV as number) === '') //只有没有在列表中搜索到数据时,才显示临时数据
|
|
|
|
|
- this.showDisplayValue = true;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- doLoadData(pid: string|number|null, level: number) {
|
|
|
|
|
- const loadData = this.loadData;
|
|
|
|
|
- if(typeof loadData === 'function') {
|
|
|
|
|
- return (loadData as LoadDataFun)(pid as string, level).then((d) => {
|
|
|
|
|
- for(let i = this.treeData.length - 1; i >= 0; i--)
|
|
|
|
|
- if(this.treeData[i].pId == pid)
|
|
|
|
|
- this.treeData.splice(i, 1);
|
|
|
|
|
- d.forEach(h => {
|
|
|
|
|
- h.level = level + 1;
|
|
|
|
|
- if(this.maxLevel > 0 && h.level >= this.maxLevel)
|
|
|
|
|
- h.isLeaf = true;
|
|
|
|
|
- if(typeof this.checkClickable === 'function')
|
|
|
|
|
- this.checkClickable(h).then((v: boolean) => h.selectable = v);
|
|
|
|
|
- else if(this.maxLevel > 0) {
|
|
|
|
|
- if(h.level >= this.maxLevel)
|
|
|
|
|
- h.selectable = false;
|
|
|
|
|
- if(this.onlyLastLevelClickable)
|
|
|
|
|
- h.selectable = (h.level == this.maxLevel);
|
|
|
|
|
- }
|
|
|
|
|
- this.treeData.push(h)
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- } else
|
|
|
|
|
- return Promise.resolve();
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取某个ID的树(正排列)
|
|
|
|
|
- */
|
|
|
|
|
- getTree(value: number) {
|
|
|
|
|
- const result = new Array<TreeDataItem>();
|
|
|
|
|
- let child : TreeDataItem|null = this.treeData.find((v) => v.id == value) as TreeDataItem;
|
|
|
|
|
- while(child) {
|
|
|
|
|
- result.unshift(child);
|
|
|
|
|
- if(child.pId == 0) child = null;
|
|
|
|
|
- else child = this.treeData.find((v) => v.id == (child as TreeDataItem).pId) as TreeDataItem;
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- },
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取某个ID的Lablel
|
|
|
|
|
- */
|
|
|
|
|
- getLableByValue(value: number) {
|
|
|
|
|
- const data = this.treeData;
|
|
|
|
|
- for (let i = 0; i < data.length; i++) {
|
|
|
|
|
- if(data[i].value == value) {
|
|
|
|
|
- return data[i].title;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return '';
|
|
|
|
|
- },
|
|
|
|
|
- /**
|
|
|
|
|
- * 重新加载数据
|
|
|
|
|
- */
|
|
|
|
|
- reload() {
|
|
|
|
|
- this.treeData = [];
|
|
|
|
|
- this.doLoadData(0, 0)
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- watch: {
|
|
|
|
|
- value(v) {
|
|
|
|
|
- this.valueV = v;
|
|
|
|
|
- },
|
|
|
|
|
- showDisplayValueBeforeEdit(v, old) {
|
|
|
|
|
- if(!old && v) {
|
|
|
|
|
- this.showDisplayValue = true;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- data() {
|
|
|
|
|
- return {
|
|
|
|
|
- showDisplayValue: false,
|
|
|
|
|
- valueV: null as null|number|string,
|
|
|
|
|
- treeData: [] as TreeDataItem[],
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- mounted() {
|
|
|
|
|
- this.valueV = this.value;
|
|
|
|
|
- if(this.showDisplayValueBeforeEdit)
|
|
|
|
|
- this.showDisplayValue = true;
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- if(this.loadAtStart) {
|
|
|
|
|
- this.treeData = [];
|
|
|
|
|
- this.doLoadData(0, 0) ;
|
|
|
|
|
- }
|
|
|
|
|
- } , 300);
|
|
|
|
|
- }
|
|
|
|
|
-});
|
|
|
|
|
-</script>
|
|
|
|
|
-
|
|
|
|
|
-<style lang="scss" scoped>
|
|
|
|
|
-.display-value {
|
|
|
|
|
- min-width: 150px;
|
|
|
|
|
- padding: 4px 11px;
|
|
|
|
|
- color: rgba(0, 0, 0, 0.85);
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- line-height: 1.5715;
|
|
|
|
|
- background-color: #fff;
|
|
|
|
|
- background-image: none;
|
|
|
|
|
- border: 1px solid #d9d9d9;
|
|
|
|
|
- border-radius: 2px;
|
|
|
|
|
-}
|
|
|
|
|
-//暗黑主题
|
|
|
|
|
-body[data-theme="dark"] {
|
|
|
|
|
- .display-value {
|
|
|
|
|
- color: #dedede;
|
|
|
|
|
- background-color: #1f1f1f;
|
|
|
|
|
- border: 1px solid #434343;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-</style>
|
|
|