😎1、优化跨租户文件上传用户所属问题 2、优化条件必填参数验证特性 3、优化前端下来列表和字典组件 4、优化表单自定义验证规则
This commit is contained in:
parent
be7cd177d1
commit
c92881a1ef
@ -52,6 +52,10 @@ public sealed class RequiredIFAttribute(
|
||||
/// </summary>
|
||||
private Operator Comparison { get; set; } = comparison;
|
||||
|
||||
public RequiredIFAttribute(string propertyName, object[] targetValues, Operator comparison = Operator.Equal) : this(propertyName, targetValues as object, comparison)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证属性值是否符合要求
|
||||
/// </summary>
|
||||
|
||||
@ -71,6 +71,11 @@ public class UploadFileInput
|
||||
/// 业务数据Id
|
||||
/// </summary>
|
||||
public long DataId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传用户Id(解决跨租户上传时用户所属不一致问题)
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -115,4 +120,9 @@ public class UploadFileFromBase64Input
|
||||
/// 业务Id
|
||||
/// </summary>
|
||||
public long? DataId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传用户Id(解决跨租户上传时用户所属不一致问题)
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
@ -174,12 +174,15 @@ public class SysFileService : IDynamicApiController, ITransient
|
||||
/// <summary>
|
||||
/// 下载指定文件Base64格式 🔖
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("下载指定文件Base64格式")]
|
||||
public async Task<string> DownloadFileBase64([FromBody] string url)
|
||||
public async Task<string> GetFileBase64([FromQuery] long id, [FromQuery] string url)
|
||||
{
|
||||
var sysFile = await _sysFileRep.AsQueryable().ClearFilter<ITenantIdFilter>().FirstAsync(u => u.Url == url) ?? throw Oops.Oh($"文件不存在");
|
||||
var sysFile = await _sysFileRep.AsQueryable().ClearFilter<ITenantIdFilter>()
|
||||
.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<SysUser>().ClearFilter<ITenantIdFilter>().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;
|
||||
|
||||
@ -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<RequestArgs> => {
|
||||
const localVarPath = `/api/sysFile/downloadFileBase64`;
|
||||
apiSysFileDownloadFilePost: async (body?: SysFile, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
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<RequestArgs> => {
|
||||
const localVarPath = `/api/sysFile/downloadFile`;
|
||||
apiSysFileFileBase64Get: async (id?: number, url?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
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<RequestArgs> => {
|
||||
apiSysFileUploadFilePostForm: async (file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, userId?: number, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
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<AxiosResponse<AdminNETResultString>>> {
|
||||
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<AxiosResponse<AdminNETResultString>>> {
|
||||
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<AxiosResponse<AdminNETResultSysFile>>> {
|
||||
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<AxiosResponse<AdminNETResultSysFile>>> {
|
||||
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<AxiosResponse<void>> {
|
||||
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<AxiosResponse<AdminNETResultString>> {
|
||||
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<AxiosResponse<AdminNETResultIActionResult>> {
|
||||
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<AxiosResponse<AdminNETResultString>> {
|
||||
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<AxiosResponse<AdminNETResultSysFile>> {
|
||||
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<AxiosResponse<AdminNETResultSysFile>> {
|
||||
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<AxiosResponse<void>> {
|
||||
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<AxiosResponse<AdminNETResultString>> {
|
||||
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<AxiosResponse<AdminNETResultIActionResult>> {
|
||||
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<AxiosResponse<AdminNETResultString>> {
|
||||
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<AxiosResponse<AdminNETResultSysFile>> {
|
||||
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<AxiosResponse<AdminNETResultSysFile>> {
|
||||
return SysFileApiFp(this.configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, userId, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
/**
|
||||
*
|
||||
|
||||
@ -67,4 +67,12 @@ export interface SysFileUploadFileBody {
|
||||
* @memberof SysFileUploadFileBody
|
||||
*/
|
||||
dataId?: number;
|
||||
|
||||
/**
|
||||
* 上传用户Id(解决跨租户上传时用户所属不一致问题)
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof SysFileUploadFileBody
|
||||
*/
|
||||
userId?: number;
|
||||
}
|
||||
|
||||
@ -75,4 +75,12 @@ export interface UploadFileFromBase64Input {
|
||||
* @memberof UploadFileFromBase64Input
|
||||
*/
|
||||
dataId?: number | null;
|
||||
|
||||
/**
|
||||
* 上传用户Id(解决跨租户上传时用户所属不一致问题)
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof UploadFileFromBase64Input
|
||||
*/
|
||||
userId?: number;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -290,26 +290,30 @@ const formattedDictData = computed(() => {
|
||||
* @computed
|
||||
* @returns {DictItem|DictItem[]|null} - 当前选中的字典项或字典项数组
|
||||
*/
|
||||
const currentDictItems = computed(() => {
|
||||
const currentDictItems = computed(() => {
|
||||
// 更严谨的空值判断,0 不算空
|
||||
const isEmpty = (val: any) =>
|
||||
val === null ||
|
||||
val === undefined ||
|
||||
(Array.isArray(val) && val.length === 0) ||
|
||||
(typeof val === 'string' && val.trim() === '');
|
||||
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;
|
||||
|
||||
let values: any[] = [];
|
||||
|
||||
if (props.multiple) {
|
||||
if (Array.isArray(state.value)) {
|
||||
// 去重并类型兼容(数字/字符串混用时也能正确匹配)
|
||||
const uniqueValues = [...new Set(state.value)];
|
||||
return formattedDictData.value.filter(item =>
|
||||
uniqueValues.some(val => val == item.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;
|
||||
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,11 +474,9 @@ const handleMutex = (newValue: any, mutexConfigs: MutexConfig[]): any => {
|
||||
* @function
|
||||
* @param {any} newValue - 新值
|
||||
*/
|
||||
const updateValue = (newValue: any) => {
|
||||
const updateValue = (newValue: any) => {
|
||||
// 先解析为数组(逗号模式下传入可能是字符串)
|
||||
let processedValue = Array.isArray(newValue) ? newValue : (typeof newValue === 'string' && props.multipleModel === MultipleModel.Comma)
|
||||
? newValue.split(',').filter(Boolean)
|
||||
: newValue;
|
||||
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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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}个字符`;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user