|
|
@@ -0,0 +1,134 @@
|
|
|
+<template>
|
|
|
+ <ASelect v-bind="attrs_" v-model:value="state" placeholder="请选择模型" @dropdown-visible-change="onDropdownVisibleChange">
|
|
|
+ <template #[item]="data" v-for="item in Object.keys($slots)">
|
|
|
+ <slot :name="item" v-bind="data || {}"></slot>
|
|
|
+ </template>
|
|
|
+ <template #dropdownRender>
|
|
|
+ <div v-if="getOptions.length" class="model-select-grid">
|
|
|
+ <div
|
|
|
+ v-for="opt in getOptions"
|
|
|
+ :key="opt.fileName"
|
|
|
+ class="model-select-grid-item"
|
|
|
+ :class="{ 'is-selected': state === opt.fileName }"
|
|
|
+ @click="handleSelect(opt)"
|
|
|
+ >
|
|
|
+ <div class="model-select-grid-thumb-wrap">
|
|
|
+ <AntImage v-if="hasOpened" :src="getFileAccessHttpUrl(opt.filePath)" :preview="true" width="64" class="model-select-thumb" />
|
|
|
+ </div>
|
|
|
+ <span class="model-select-name">{{ opt.fileName + deviceType }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </ASelect>
|
|
|
+</template>
|
|
|
+<script lang="ts">
|
|
|
+ import { defineComponent, ref, computed, unref } from 'vue';
|
|
|
+ import { Select as ASelect, Image as AntImage } from 'ant-design-vue';
|
|
|
+ import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
|
|
+ import { useAttrs } from '/@/hooks/core/useAttrs';
|
|
|
+ import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
|
|
+ import { propTypes } from '/@/utils/propTypes';
|
|
|
+ import { useModelFileStore } from '/@/store/modules/modelFile';
|
|
|
+ import { storeToRefs } from 'pinia';
|
|
|
+
|
|
|
+ type OptionsItem = { label: string; value: string; fileName: string; filePath: string };
|
|
|
+
|
|
|
+ export default defineComponent({
|
|
|
+ name: 'ModelSelect',
|
|
|
+ components: { ASelect, AntImage },
|
|
|
+ inheritAttrs: false,
|
|
|
+ props: {
|
|
|
+ value: propTypes.oneOfType([propTypes.string, propTypes.number]),
|
|
|
+ deviceType: propTypes.string.def(''),
|
|
|
+ },
|
|
|
+ emits: ['change', 'update:value'],
|
|
|
+ setup(props, { emit }) {
|
|
|
+ const emitData = ref<any[]>([]);
|
|
|
+ const attrs = useAttrs();
|
|
|
+ const hasOpened = ref(false);
|
|
|
+
|
|
|
+ const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
|
|
+
|
|
|
+ const modelFileStore = useModelFileStore();
|
|
|
+ const { modelFileData } = storeToRefs(modelFileStore);
|
|
|
+
|
|
|
+ const attrs_ = computed(() => {
|
|
|
+ const obj: any = { ...unref(attrs) };
|
|
|
+ if (obj && obj['onUpdate:value']) {
|
|
|
+ delete obj['onUpdate:value'];
|
|
|
+ }
|
|
|
+ return obj;
|
|
|
+ });
|
|
|
+
|
|
|
+ const getOptions = computed((): OptionsItem[] => {
|
|
|
+ const key = props.deviceType;
|
|
|
+ if (!key || !modelFileData.value) return [];
|
|
|
+ console.log('debug m', modelFileData.value);
|
|
|
+ const items = modelFileData.value[key.split('_')[0]];
|
|
|
+ if (!items) return [];
|
|
|
+ return items.map((item) => ({
|
|
|
+ label: item.fileName,
|
|
|
+ value: item.fileName,
|
|
|
+ fileName: item.fileName,
|
|
|
+ filePath: item.filePath,
|
|
|
+ }));
|
|
|
+ });
|
|
|
+
|
|
|
+ function onDropdownVisibleChange(visible: boolean) {
|
|
|
+ hasOpened.value = visible;
|
|
|
+ }
|
|
|
+
|
|
|
+ function handleSelect(opt: OptionsItem) {
|
|
|
+ state.value = opt.fileName;
|
|
|
+ emit('update:value', opt.fileName);
|
|
|
+ }
|
|
|
+
|
|
|
+ return { state, attrs_, getOptions, getFileAccessHttpUrl, hasOpened, onDropdownVisibleChange, handleSelect };
|
|
|
+ },
|
|
|
+ });
|
|
|
+</script>
|
|
|
+<style scoped>
|
|
|
+ .model-select-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 8px;
|
|
|
+ max-height: 350px;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+ .model-select-grid-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+ padding: 8px;
|
|
|
+ border: 1px solid #f0f0f0;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition:
|
|
|
+ border-color 0.2s,
|
|
|
+ box-shadow 0.2s;
|
|
|
+ }
|
|
|
+ .model-select-grid-item:hover {
|
|
|
+ border-color: #1890ff;
|
|
|
+ box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
|
|
|
+ }
|
|
|
+ .model-select-grid-item.is-selected {
|
|
|
+ border-color: #1890ff;
|
|
|
+ background: #e6f7ff;
|
|
|
+ }
|
|
|
+ .model-select-grid-thumb-wrap {
|
|
|
+ line-height: 0;
|
|
|
+ }
|
|
|
+ .model-select-thumb {
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #f0f0f0;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ .model-select-name {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #333;
|
|
|
+ text-align: center;
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+</style>
|