yumi-admin/apps/src/components/account-input.vue
2026-04-22 17:06:02 +08:00

227 lines
5.1 KiB
Vue

<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import { useAccessStore } from '@vben/stores';
import { Input, Select } from 'antdv-next';
import {
getAllowedSysOrigins,
getDisplayableSysOriginOptions,
} from '#/views/system/shared';
import SysOriginSelect from '#/components/sys-origin-select.vue';
type AccountSelectType = 'LONG' | 'SHORT';
const ACCOUNT_TYPE_OPTIONS = [
{ label: '长ID', value: 'LONG' },
{ label: '短ID', value: 'SHORT' },
] satisfies Array<{ label: string; value: AccountSelectType }>;
const props = withDefaults(
defineProps<{
defaultSelectType?: AccountSelectType;
placeholder?: string;
sysOrigin?: string;
type?: string;
value?: number | string;
}>(),
{
defaultSelectType: 'SHORT',
placeholder: '',
sysOrigin: '',
type: 'USER',
value: '',
},
);
const emit = defineEmits<{
'update:value': [string];
}>();
const accessStore = useAccessStore();
const inputValue = ref('');
const selectType = ref<AccountSelectType>('SHORT');
const sysOriginType = ref('');
const sysOriginOptions = computed(() =>
getAllowedSysOrigins(accessStore.accessCodes || []),
);
const displaySysOriginOptions = computed(() =>
getDisplayableSysOriginOptions(sysOriginOptions.value),
);
const showSysOriginTypeSelect = computed(
() => !props.sysOrigin && displaySysOriginOptions.value.length > 0,
);
const sysOriginVal = computed(() => props.sysOrigin || sysOriginType.value);
function filterString(value: unknown) {
if (value === null || value === undefined || value === '') {
return '';
}
return String(value).replace(/[^\d]/g, '');
}
function parseEncodedValue(value: unknown) {
const raw = String(value ?? '');
if (!raw) {
return {
accountType: '',
content: '',
sysOrigin: '',
};
}
const match = raw.match(/^\*(.*)\*$/);
if (!match) {
return {
accountType: '',
content: raw,
sysOrigin: '',
};
}
const body = match[1] || '';
return {
accountType: body.match(/accountType:([^,]*)/)?.[1] || '',
content: body.match(/content:(.*)$/)?.[1] || '',
sysOrigin: body.match(/sysOrigin:([^,]*)/)?.[1] || '',
};
}
function syncFromValue(value: unknown) {
const parsed = parseEncodedValue(value);
const nextType = (parsed.accountType ||
props.defaultSelectType ||
'SHORT') as AccountSelectType;
selectType.value = nextType;
inputValue.value =
nextType === 'LONG' ? filterString(parsed.content) : parsed.content;
if (!props.sysOrigin) {
if (parsed.sysOrigin) {
sysOriginType.value = parsed.sysOrigin;
return;
}
if (!sysOriginType.value && sysOriginOptions.value.length > 0) {
sysOriginType.value = String(sysOriginOptions.value[0]?.value || '');
}
}
}
function buildValue() {
if (!inputValue.value) {
return '';
}
return `*type:${props.type},accountType:${selectType.value},sysOrigin:${sysOriginVal.value},content:${inputValue.value}*`;
}
function emitValue() {
emit('update:value', buildValue());
}
function handleInput(value: string) {
inputValue.value =
selectType.value === 'LONG' ? filterString(value) : String(value || '');
emitValue();
}
function handleSelectTypeChange(value: AccountSelectType) {
selectType.value = value;
if (selectType.value === 'LONG') {
inputValue.value = filterString(inputValue.value);
}
emitValue();
}
function handleSysOriginTypeChange(
value: Array<number | string> | number | string | null | undefined,
) {
const nextValue = Array.isArray(value) ? value[0] : value;
sysOriginType.value = nextValue === null || nextValue === undefined ? '' : String(nextValue);
emitValue();
}
watch(
() => props.value,
(value) => {
syncFromValue(value);
},
{ immediate: true },
);
watch(
() => props.defaultSelectType,
(value) => {
if (!props.value) {
selectType.value = (value || 'SHORT') as AccountSelectType;
}
},
{ immediate: true },
);
watch(
sysOriginOptions,
(options) => {
if (!props.sysOrigin && !sysOriginType.value && options.length > 0) {
sysOriginType.value = String(options[0]?.value || '');
}
},
{ immediate: true },
);
watch(
() => props.sysOrigin,
() => {
emitValue();
},
);
</script>
<template>
<div class="account-input">
<Select
v-model:value="selectType"
:options="ACCOUNT_TYPE_OPTIONS"
class="account-input__type"
:disabled="!sysOriginVal"
@change="handleSelectTypeChange"
/>
<Input
:value="inputValue"
allow-clear
class="account-input__field"
:disabled="!sysOriginVal"
:placeholder="placeholder"
@update:value="handleInput"
/>
<SysOriginSelect
v-if="showSysOriginTypeSelect && selectType !== 'LONG'"
v-model:value="sysOriginType"
class="account-input__origin"
:options="displaySysOriginOptions"
@change="handleSysOriginTypeChange"
/>
</div>
</template>
<style scoped>
.account-input {
display: flex;
gap: 8px;
width: 100%;
}
.account-input__type {
flex: 0 0 88px;
}
.account-input__field {
flex: 1 1 auto;
min-width: 0;
}
.account-input__origin {
flex: 0 0 120px;
}
</style>