diff --git a/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs b/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs
index 23d1eaca..f86d5cda 100644
--- a/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs
+++ b/Admin.NET/Admin.NET.Core/Attribute/RequiredIFAttribute.cs
@@ -52,6 +52,10 @@ public sealed class RequiredIFAttribute(
///
private Operator Comparison { get; set; } = comparison;
+ public RequiredIFAttribute(string propertyName, object[] targetValues, Operator comparison = Operator.Equal) : this(propertyName, targetValues as object, comparison)
+ {
+ }
+
///
/// 验证属性值是否符合要求
///
diff --git a/Admin.NET/Admin.NET.Core/Service/File/Dto/FileInput.cs b/Admin.NET/Admin.NET.Core/Service/File/Dto/FileInput.cs
index dd75b0be..8b48003d 100644
--- a/Admin.NET/Admin.NET.Core/Service/File/Dto/FileInput.cs
+++ b/Admin.NET/Admin.NET.Core/Service/File/Dto/FileInput.cs
@@ -71,6 +71,11 @@ public class UploadFileInput
/// 业务数据Id
///
public long DataId { get; set; }
+
+ ///
+ /// 上传用户Id(解决跨租户上传时用户所属不一致问题)
+ ///
+ public long UserId { get; set; }
}
///
@@ -115,4 +120,9 @@ public class UploadFileFromBase64Input
/// 业务Id
///
public long? DataId { get; set; }
+
+ ///
+ /// 上传用户Id(解决跨租户上传时用户所属不一致问题)
+ ///
+ public long UserId { get; set; }
}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs b/Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs
index 5f2aae9e..b0a965f6 100644
--- a/Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs
+++ b/Admin.NET/Admin.NET.Core/Service/File/SysFileService.cs
@@ -174,12 +174,15 @@ public class SysFileService : IDynamicApiController, ITransient
///
/// 下载指定文件Base64格式 🔖
///
+ ///
///
///
[DisplayName("下载指定文件Base64格式")]
- public async Task DownloadFileBase64([FromBody] string url)
+ public async Task GetFileBase64([FromQuery] long id, [FromQuery] string url)
{
- var sysFile = await _sysFileRep.AsQueryable().ClearFilter().FirstAsync(u => u.Url == url) ?? throw Oops.Oh($"文件不存在");
+ var sysFile = await _sysFileRep.AsQueryable().ClearFilter()
+ .WhereIF(id > 0, u => u.Id == id)
+ .WhereIF(!string.IsNullOrWhiteSpace(url), u => u.Url == url).FirstAsync() ?? throw Oops.Oh($"文件不存在");
return await _customFileProvider.DownloadFileBase64Async(sysFile);
}
@@ -322,8 +325,21 @@ public class SysFileService : IDynamicApiController, ITransient
newFile.FilePath = path;
newFile.FileMd5 = fileMd5;
- var finalName = newFile.Id + suffix; // 文件最终名称
+ // 解决跨租户上传时用户所属不一致问题
+ if (input.UserId > 0)
+ {
+ var user = await _sysFileRep.Context.Queryable().ClearFilter().FirstAsync(u => u.Id == input.UserId);
+ if (user != null)
+ {
+ newFile.CreateUserId = user.Id;
+ newFile.CreateUserName = user.RealName;
+ newFile.CreateOrgId = user.OrgId;
+ newFile.CreateOrgName = user.SysOrg?.Name;
+ newFile.TenantId = user.TenantId;
+ }
+ }
+ var finalName = newFile.Id + suffix; // 文件最终名称
newFile = await _customFileProvider.UploadFileAsync(input.File, newFile, path, finalName);
await _sysFileRep.AsInsertable(newFile).ExecuteCommandAsync();
return newFile;
diff --git a/Web/src/api-services/system/apis/sys-file-api.ts b/Web/src/api-services/system/apis/sys-file-api.ts
index d4270adb..bf5880c6 100644
--- a/Web/src/api-services/system/apis/sys-file-api.ts
+++ b/Web/src/api-services/system/apis/sys-file-api.ts
@@ -83,13 +83,13 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
},
/**
*
- * @summary 下载指定文件Base64格式 🔖
- * @param {string} [body]
+ * @summary 根据文件Id或Url下载 🔖
+ * @param {SysFile} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- apiSysFileDownloadFileBase64Post: async (body?: string, options: AxiosRequestConfig = {}): Promise => {
- const localVarPath = `/api/sysFile/downloadFileBase64`;
+ apiSysFileDownloadFilePost: async (body?: SysFile, options: AxiosRequestConfig = {}): Promise => {
+ const localVarPath = `/api/sysFile/downloadFile`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
@@ -131,20 +131,21 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
},
/**
*
- * @summary 根据文件Id或Url下载 🔖
- * @param {SysFile} [body]
+ * @summary 下载指定文件Base64格式 🔖
+ * @param {number} [id]
+ * @param {string} [url]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- apiSysFileDownloadFilePost: async (body?: SysFile, options: AxiosRequestConfig = {}): Promise => {
- const localVarPath = `/api/sysFile/downloadFile`;
+ apiSysFileFileBase64Get: async (id?: number, url?: string, options: AxiosRequestConfig = {}): Promise => {
+ const localVarPath = `/api/sysFile/fileBase64`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
- const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+ const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
@@ -157,7 +158,13 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
- localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
+ if (id !== undefined) {
+ localVarQueryParameter['id'] = id;
+ }
+
+ if (url !== undefined) {
+ localVarQueryParameter['url'] = url;
+ }
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
@@ -169,8 +176,6 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
- const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
- localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
@@ -634,10 +639,11 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
* @param {boolean} [isPublic]
* @param {string} [allowSuffix]
* @param {number} [dataId]
+ * @param {number} [userId]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- apiSysFileUploadFilePostForm: async (file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options: AxiosRequestConfig = {}): Promise => {
+ apiSysFileUploadFilePostForm: async (file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, userId?: number, options: AxiosRequestConfig = {}): Promise => {
const localVarPath = `/api/sysFile/uploadFile`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@@ -684,6 +690,10 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
localVarFormParams.append('DataId', dataId as any);
}
+ if (userId !== undefined) {
+ localVarFormParams.append('UserId', userId as any);
+ }
+
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
@@ -941,20 +951,6 @@ export const SysFileApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
- /**
- *
- * @summary 下载指定文件Base64格式 🔖
- * @param {string} [body]
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- async apiSysFileDownloadFileBase64Post(body?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> {
- const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileDownloadFileBase64Post(body, options);
- return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
- const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
- return axios.request(axiosRequestArgs);
- };
- },
/**
*
* @summary 根据文件Id或Url下载 🔖
@@ -969,6 +965,21 @@ export const SysFileApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
+ /**
+ *
+ * @summary 下载指定文件Base64格式 🔖
+ * @param {number} [id]
+ * @param {string} [url]
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async apiSysFileFileBase64Get(id?: number, url?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> {
+ const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileFileBase64Get(id, url, options);
+ return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+ const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+ return axios.request(axiosRequestArgs);
+ };
+ },
/**
*
* @summary 根据文件Id集合获取文件 🔖
@@ -1105,11 +1116,12 @@ export const SysFileApiFp = function(configuration?: Configuration) {
* @param {boolean} [isPublic]
* @param {string} [allowSuffix]
* @param {number} [dataId]
+ * @param {number} [userId]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> {
- const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, options);
+ async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, userId?: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise>> {
+ const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, userId, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
@@ -1192,16 +1204,6 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
async apiSysFileDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig): Promise> {
return SysFileApiFp(configuration).apiSysFileDeletePost(body, options).then((request) => request(axios, basePath));
},
- /**
- *
- * @summary 下载指定文件Base64格式 🔖
- * @param {string} [body]
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- */
- async apiSysFileDownloadFileBase64Post(body?: string, options?: AxiosRequestConfig): Promise> {
- return SysFileApiFp(configuration).apiSysFileDownloadFileBase64Post(body, options).then((request) => request(axios, basePath));
- },
/**
*
* @summary 根据文件Id或Url下载 🔖
@@ -1212,6 +1214,17 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
async apiSysFileDownloadFilePost(body?: SysFile, options?: AxiosRequestConfig): Promise> {
return SysFileApiFp(configuration).apiSysFileDownloadFilePost(body, options).then((request) => request(axios, basePath));
},
+ /**
+ *
+ * @summary 下载指定文件Base64格式 🔖
+ * @param {number} [id]
+ * @param {string} [url]
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async apiSysFileFileBase64Get(id?: number, url?: string, options?: AxiosRequestConfig): Promise> {
+ return SysFileApiFp(configuration).apiSysFileFileBase64Get(id, url, options).then((request) => request(axios, basePath));
+ },
/**
*
* @summary 根据文件Id集合获取文件 🔖
@@ -1312,11 +1325,12 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
* @param {boolean} [isPublic]
* @param {string} [allowSuffix]
* @param {number} [dataId]
+ * @param {number} [userId]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options?: AxiosRequestConfig): Promise> {
- return SysFileApiFp(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, options).then((request) => request(axios, basePath));
+ async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, userId?: number, options?: AxiosRequestConfig): Promise> {
+ return SysFileApiFp(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, userId, options).then((request) => request(axios, basePath));
},
/**
*
@@ -1381,17 +1395,6 @@ export class SysFileApi extends BaseAPI {
public async apiSysFileDeletePost(body?: BaseIdInput, options?: AxiosRequestConfig) : Promise> {
return SysFileApiFp(this.configuration).apiSysFileDeletePost(body, options).then((request) => request(this.axios, this.basePath));
}
- /**
- *
- * @summary 下载指定文件Base64格式 🔖
- * @param {string} [body]
- * @param {*} [options] Override http request option.
- * @throws {RequiredError}
- * @memberof SysFileApi
- */
- public async apiSysFileDownloadFileBase64Post(body?: string, options?: AxiosRequestConfig) : Promise> {
- return SysFileApiFp(this.configuration).apiSysFileDownloadFileBase64Post(body, options).then((request) => request(this.axios, this.basePath));
- }
/**
*
* @summary 根据文件Id或Url下载 🔖
@@ -1403,6 +1406,18 @@ export class SysFileApi extends BaseAPI {
public async apiSysFileDownloadFilePost(body?: SysFile, options?: AxiosRequestConfig) : Promise> {
return SysFileApiFp(this.configuration).apiSysFileDownloadFilePost(body, options).then((request) => request(this.axios, this.basePath));
}
+ /**
+ *
+ * @summary 下载指定文件Base64格式 🔖
+ * @param {number} [id]
+ * @param {string} [url]
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof SysFileApi
+ */
+ public async apiSysFileFileBase64Get(id?: number, url?: string, options?: AxiosRequestConfig) : Promise> {
+ return SysFileApiFp(this.configuration).apiSysFileFileBase64Get(id, url, options).then((request) => request(this.axios, this.basePath));
+ }
/**
*
* @summary 根据文件Id集合获取文件 🔖
@@ -1512,12 +1527,13 @@ export class SysFileApi extends BaseAPI {
* @param {boolean} [isPublic]
* @param {string} [allowSuffix]
* @param {number} [dataId]
+ * @param {number} [userId]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysFileApi
*/
- public async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options?: AxiosRequestConfig) : Promise> {
- return SysFileApiFp(this.configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, options).then((request) => request(this.axios, this.basePath));
+ public async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, userId?: number, options?: AxiosRequestConfig) : Promise> {
+ return SysFileApiFp(this.configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, userId, options).then((request) => request(this.axios, this.basePath));
}
/**
*
diff --git a/Web/src/api-services/system/models/sys-file-upload-file-body.ts b/Web/src/api-services/system/models/sys-file-upload-file-body.ts
index 81c34be5..f018f968 100644
--- a/Web/src/api-services/system/models/sys-file-upload-file-body.ts
+++ b/Web/src/api-services/system/models/sys-file-upload-file-body.ts
@@ -67,4 +67,12 @@ export interface SysFileUploadFileBody {
* @memberof SysFileUploadFileBody
*/
dataId?: number;
+
+ /**
+ * 上传用户Id(解决跨租户上传时用户所属不一致问题)
+ *
+ * @type {number}
+ * @memberof SysFileUploadFileBody
+ */
+ userId?: number;
}
diff --git a/Web/src/api-services/system/models/upload-file-from-base64-input.ts b/Web/src/api-services/system/models/upload-file-from-base64-input.ts
index 182744b8..494e982a 100644
--- a/Web/src/api-services/system/models/upload-file-from-base64-input.ts
+++ b/Web/src/api-services/system/models/upload-file-from-base64-input.ts
@@ -75,4 +75,12 @@ export interface UploadFileFromBase64Input {
* @memberof UploadFileFromBase64Input
*/
dataId?: number | null;
+
+ /**
+ * 上传用户Id(解决跨租户上传时用户所属不一致问题)
+ *
+ * @type {number}
+ * @memberof UploadFileFromBase64Input
+ */
+ userId?: number;
}
diff --git a/Web/src/components/selector/pulldownSelecter.vue b/Web/src/components/selector/pulldownSelecter.vue
index 50caff5c..4c88c1f8 100644
--- a/Web/src/components/selector/pulldownSelecter.vue
+++ b/Web/src/components/selector/pulldownSelecter.vue
@@ -292,6 +292,8 @@ const handleChange = (row: any) => {
// 选择器下拉框显示隐藏事件
const selectVisibleChange = (visible: boolean) => {
if (visible) {
+ state.tableData.items = [];
+ state.tableData.total = 0;
state.tableQuery[props.keywordProp] = undefined;
handleQuery();
}
diff --git a/Web/src/components/sysDict/sysDict.vue b/Web/src/components/sysDict/sysDict.vue
index 2301dbfb..5eaedbae 100644
--- a/Web/src/components/sysDict/sysDict.vue
+++ b/Web/src/components/sysDict/sysDict.vue
@@ -290,26 +290,30 @@ const formattedDictData = computed(() => {
* @computed
* @returns {DictItem|DictItem[]|null} - 当前选中的字典项或字典项数组
*/
- const currentDictItems = computed(() => {
- // 更严谨的空值判断,0 不算空
- const isEmpty = (val: any) =>
- val === null ||
- val === undefined ||
- (Array.isArray(val) && val.length === 0) ||
- (typeof val === 'string' && val.trim() === '');
+const currentDictItems = computed(() => {
+ // 更严谨的空值判断,0 不算空
+ const isEmpty = (val: any) => val === null || val === undefined || (Array.isArray(val) && val.length === 0) || (typeof val === 'string' && val.trim() === '');
- if (isEmpty(state.value)) return null;
+ if (isEmpty(state.value)) return null;
- if (Array.isArray(state.value)) {
- // 去重并类型兼容(数字/字符串混用时也能正确匹配)
- const uniqueValues = [...new Set(state.value)];
- return formattedDictData.value.filter(item =>
- uniqueValues.some(val => val == item.value)
- );
- }
+ let values: any[] = [];
- // 单选时类型兼容
- return formattedDictData.value.find(item => item.value == state.value) || null;
+ if (props.multiple) {
+ if (Array.isArray(state.value)) {
+ values = state.value;
+ } else if (typeof state.value === 'string' && props.renderAs === 'tag') {
+ values = state.value.split(',').filter((v) => v !== '');
+ } else if (state.value !== undefined && state.value !== null && state.value !== '') {
+ values = [state.value];
+ }
+ console.log('[g-sys-dict] 解析多选值:', state.value, values);
+ // 去重并类型兼容
+ const uniqueValues = [...new Set(values)];
+ return formattedDictData.value.filter((item) => uniqueValues.some((val) => val == item.value));
+ }
+
+ // 单选时类型兼容
+ return formattedDictData.value.find((item) => item.value == state.value) || null;
});
/**
@@ -376,6 +380,22 @@ const parseMultipleValue = (value: any): any => {
return props.multiple ? [] : value;
}
+ // 多选且字符串,自动按逗号分割
+ if (props.multiple && typeof value === 'string') {
+ if (value.trim().startsWith('[') && value.trim().endsWith(']')) {
+ try {
+ return JSON.parse(value.trim());
+ } catch {
+ return [];
+ }
+ }
+ // 只要是多选+字符串,默认逗号分割
+ return value
+ .split(',')
+ .map((v) => v.trim())
+ .filter((v) => v !== '');
+ }
+
// 处理数字
if (typeof value === 'number' && !state.conversion) {
try {
@@ -388,29 +408,6 @@ const parseMultipleValue = (value: any): any => {
}
}
- // 处理字符串值
- if (typeof value === 'string') {
- const trimmedValue = value.trim();
-
- // 处理JSON数组格式
- if (trimmedValue.startsWith('[') && trimmedValue.endsWith(']')) {
- try {
- return JSON.parse(trimmedValue);
- } catch (error) {
- console.warn('[g-sys-dict] 解析多选值失败:', error);
- return [];
- }
- }
-
- // 处理逗号分隔格式
- if (props.multipleModel === MultipleModel.Comma && trimmedValue.includes(',')) {
- return trimmedValue.split(',');
- }
-
- // 处理单个值情况
- return props.multiple ? [trimmedValue] : trimmedValue;
- }
-
// 其他情况直接返回
return value;
};
@@ -477,36 +474,34 @@ const handleMutex = (newValue: any, mutexConfigs: MutexConfig[]): any => {
* @function
* @param {any} newValue - 新值
*/
- const updateValue = (newValue: any) => {
- // 先解析为数组(逗号模式下传入可能是字符串)
- let processedValue = Array.isArray(newValue) ? newValue : (typeof newValue === 'string' && props.multipleModel === MultipleModel.Comma)
- ? newValue.split(',').filter(Boolean)
- : newValue;
+const updateValue = (newValue: any) => {
+ // 先解析为数组(逗号模式下传入可能是字符串)
+ let processedValue = Array.isArray(newValue) ? newValue : typeof newValue === 'string' && props.multipleModel === MultipleModel.Comma ? newValue.split(',').filter(Boolean) : newValue;
- // 处理互斥逻辑
- if (props.mutexConfigs && props.mutexConfigs.length > 0) {
- processedValue = handleMutex(processedValue, props.mutexConfigs);
- }
+ // 处理互斥逻辑
+ if (props.mutexConfigs && props.mutexConfigs.length > 0) {
+ processedValue = handleMutex(processedValue, props.mutexConfigs);
+ }
- let emitValue = processedValue;
- if (props.multipleModel === MultipleModel.Comma) {
- if (Array.isArray(processedValue)) {
- emitValue = processedValue.length > 0 ? processedValue.sort().join(',') : '';
- } else if (processedValue === null || processedValue === undefined) {
- emitValue = undefined;
- }
- } else {
- if (Array.isArray(processedValue)) {
- emitValue = processedValue.length > 0 ? processedValue.sort() : [];
- } else if (processedValue === null || processedValue === undefined) {
- emitValue = undefined;
- }
- }
- console.log('[g-sys-dict] 更新值:', { newValue, processedValue, emitValue });
+ let emitValue = processedValue;
+ if (props.multipleModel === MultipleModel.Comma) {
+ if (Array.isArray(processedValue)) {
+ emitValue = processedValue.length > 0 ? processedValue.sort().join(',') : '';
+ } else if (processedValue === null || processedValue === undefined) {
+ emitValue = undefined;
+ }
+ } else {
+ if (Array.isArray(processedValue)) {
+ emitValue = processedValue.length > 0 ? processedValue.sort() : [];
+ } else if (processedValue === null || processedValue === undefined) {
+ emitValue = undefined;
+ }
+ }
+ console.log('[g-sys-dict] 更新值:', { newValue, processedValue, emitValue });
- state.value = processedValue;
- emit('update:modelValue', emitValue === '' || emitValue?.length === 0 ? undefined : emitValue);
- emit('change', state.value, currentDictItems, state.dictData);
+ state.value = processedValue;
+ emit('update:modelValue', emitValue === '' || emitValue?.length === 0 ? undefined : emitValue);
+ emit('change', state.value, currentDictItems, state.dictData);
};
/**
diff --git a/Web/src/theme/vxeTable.scss b/Web/src/theme/vxeTable.scss
index 1ca7372b..2031792d 100644
--- a/Web/src/theme/vxeTable.scss
+++ b/Web/src/theme/vxeTable.scss
@@ -135,3 +135,10 @@
.vxe-modal--close-btn:hover {
color: red !important;
}
+
+// 解决el-dialog和vxe-tooltip弹出层z-index冲突问题
+.vxe-modal--wrapper,
+.vxe-tooltip--wrapper,
+.vxe-table--filter-wrapper{
+ z-index: 2023 !important;
+}
diff --git a/Web/src/utils/formValidator.ts b/Web/src/utils/formValidator.ts
index fe762266..02222829 100644
--- a/Web/src/utils/formValidator.ts
+++ b/Web/src/utils/formValidator.ts
@@ -31,7 +31,7 @@ class ValidationBuilder {
constructor(config: ValidatorConfig) {
this.prop = config.prop;
- this.label = config.label || config.prop;
+ this.label = config.label || '此项';
this.customMessages = config.customMessages || {};
this.defaultTrigger = config.trigger || 'blur'; // 设置默认触发方式
}
@@ -75,6 +75,18 @@ class ValidationBuilder {
return this;
}
+ // 条件必填验证
+ requiredIf(required?: boolean, message?: string): ValidationBuilder {
+ const defaultMessage = `${this.label}不能为空`;
+ const rule: ValidationRule = {
+ type: 'required', // 添加 type 字段
+ message: message || this.getMessage('required', defaultMessage),
+ required: required,
+ };
+ this.rules.push(rule);
+ return this;
+ }
+
// 最小长度验证
min(len: number, message?: string): ValidationBuilder {
const defaultMessage = `${this.label}最少输入${len}个字符`;