😎1、职位管理页面增加导入、导出、下载模板示例 2、调整翻译文件 3、更新前端请求文件 4、调整服务API顺序

This commit is contained in:
zuohuaijun 2025-07-24 17:30:18 +08:00
parent a68da25ed0
commit bd5afe83ec
33 changed files with 516 additions and 12 deletions

View File

@ -63,6 +63,8 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
new SysMenu{ Id=1310000000154, Pid=1310000000151, Title="编辑", Permission="sysPos/update", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000155, Pid=1310000000151, Title="增加", Permission="sysPos/add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000156, Pid=1310000000151, Title="删除", Permission="sysPos/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000157, Pid=1310000000151, Title="导入", Permission="sysPos/import", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000158, Pid=1310000000151, Title="导出", Permission="sysPos/export", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
new SysMenu{ Id=1310000000161, Pid=1310000000101, Title="个人中心", Path="/system/userCenter", Name="sysUserCenter", Component="/system/user/component/userCenter",Icon="ele-Medal", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
new SysMenu{ Id=1310000000162, Pid=1310000000161, Title="修改密码", Permission="sysUser/changePwd", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },

View File

@ -12,7 +12,7 @@ namespace Admin.NET.Core.Service;
/// <param name="rep"></param>
/// <param name="um"></param>
/// <param name="cache"></param>
[ApiDescriptionSettings(Order = 440, Description = "代码生成模板配置")]
[ApiDescriptionSettings(Order = 245, Description = "代码生成模板配置")]
public class SysColumnCustomService(SqlSugarRepository<SysColumnCustom> rep, UserManager um, SysCacheService cache) : IDynamicApiController, ITransient
{
/// <summary>

View File

@ -0,0 +1,53 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 导入/导出职位数据映射
/// </summary>
[ExcelImporter(IsLabelingError = true)]
[ExcelExporter(Name = "职位数据", TableStyle = OfficeOpenXml.Table.TableStyles.None, AutoFitAllColumn = true)]
public class PosDto
{
/// <summary>
/// 名称
/// </summary>
[ImporterHeader(Name = "名称")]
[ExporterHeader(DisplayName = "名称", IsBold = true)]
public string Name { get; set; }
/// <summary>
/// 编码
/// </summary>
[ImporterHeader(Name = "编码")]
[ExporterHeader(DisplayName = "编码", IsBold = true)]
public string Code { get; set; }
/// <summary>
/// 排序
/// </summary>
[ImporterHeader(Name = "排序")]
[ExporterHeader(DisplayName = "排序", IsBold = true)]
public int OrderNo { get; set; }
/// <summary>
/// 备注
/// </summary>
[ImporterHeader(Name = "备注")]
[ExporterHeader(DisplayName = "备注", IsBold = true)]
public string Remark { get; set; }
/// <summary>
/// 状态
/// </summary>
[ImporterHeader(Name = "状态")]
[Required(ErrorMessage = "状态不能为空")]
[ValueMapping("启用", 1)]
[ValueMapping("停用", 2)]
[ExporterHeader(DisplayName = "状态", IsBold = true)]
public StatusEnum Status { get; set; }
}

View File

@ -122,4 +122,55 @@ public class SysPosService : IDynamicApiController, ITransient
await _sysPosRep.DeleteByIdAsync(input.Id);
}
/// <summary>
/// 导入职位 🔖
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[DisplayName("导入职位")]
public async Task Import([Required] IFormFile file)
{
var tFile = await App.GetRequiredService<SysFileService>().UploadFile(new UploadFileInput { File = file });
var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, tFile.FilePath, tFile.Id.ToString() + tFile.Suffix);
IImporter importer = new ExcelImporter();
var res = await importer.Import<PosDto>(filePath);
if (res == null || res.Exception != null)
throw Oops.Oh(res.Exception);
var importData = res.Data.ToList();
// 按照编码条件进行批量更新或者新增
await _sysPosRep.Context.Storageable(importData.Adapt<List<SysPos>>()).WhereColumns(u => u.Code).ExecuteCommandAsync();
}
/// <summary>
/// 导出职位 🔖
/// </summary>
/// <returns></returns>
[DisplayName("导出职位")]
public async Task<IActionResult> Export(PosInput input)
{
var posList = await _sysPosRep.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name == input.Name)
.WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code == input.Code)
.OrderBy(u => u.CreateTime, OrderByType.Desc)
.Select<PosDto>().ToListAsync();
if (posList == null || posList.Count < 1)
throw Oops.Oh("数据为空,导出已取消");
var res = await ((IExcelExporter)new ExcelExporter()).ExportAsByteArray(posList);
return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "职位列表.xlsx" };
}
/// <summary>
/// 下载职位导入模板 🔖
/// </summary>
/// <returns></returns>
public async Task<IActionResult> DownloadTemplate()
{
IImporter Importer = new ExcelImporter();
var res = await Importer.GenerateTemplateBytes<PosDto>();
return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = "职位导入模板.xlsx" };
}
}

View File

@ -11,7 +11,7 @@ namespace Admin.NET.Core.Service;
/// <summary>
/// 系统报表配置服务
/// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表配置")]
[ApiDescriptionSettings(Order = 245, Description = "报表配置")]
public class SysReportConfigService : IDynamicApiController, ITransient
{
private readonly SqlSugarRepository<SysReportConfig> _reportConfigRep;

View File

@ -11,7 +11,7 @@ namespace Admin.NET.Core.Service;
/// <summary>
/// 系统报表数据源服务
/// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表数据源")]
[ApiDescriptionSettings(Order = 245, Description = "报表数据源")]
public class SysReportDataSourceService : IDynamicApiController, ITransient
{
private readonly SqlSugarRepository<SysReportDataSource> _reportDataSourceRep;

View File

@ -9,7 +9,7 @@ namespace Admin.NET.Core.Service;
/// <summary>
/// 系统报表分组服务
/// </summary>
[ApiDescriptionSettings(Order = 500, Description = "报表分组")]
[ApiDescriptionSettings(Order = 245, Description = "报表分组")]
public class SysReportGroupService : IDynamicApiController, ITransient
{
private readonly SqlSugarRepository<SysReportGroup> _reportGroupRep;

View File

@ -83,7 +83,7 @@
"vue-router": "^4.5.1",
"vue-signature-pad": "^3.0.2",
"vue3-tree-org": "^4.2.2",
"vxe-pc-ui": "^4.7.23",
"vxe-pc-ui": "^4.7.24",
"vxe-table": "^4.14.5",
"xe-utils": "^3.7.8",
"xlsx-js-style": "^1.2.0"

View File

@ -18,10 +18,12 @@ import { Configuration } from '../configuration';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
import { AddPosInput } from '../models';
import { AdminNETResultIActionResult } from '../models';
import { AdminNETResultListPosOutput } from '../models';
import { AdminNETResultSqlSugarPagedListPagePosOutput } from '../models';
import { DeletePosInput } from '../models';
import { PagePosInput } from '../models';
import { PosInput } from '../models';
import { UpdatePosInput } from '../models';
/**
* SysPosApi - axios parameter creator
@ -125,6 +127,149 @@ export const SysPosApiAxiosParamCreator = function (configuration?: Configuratio
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysPosDownloadTemplatePost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysPos/downloadTemplate`;
// 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 localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {PosInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysPosExportPost: async (body?: PosInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysPos/export`;
// 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 localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
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,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {Blob} [file]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysPosImportPostForm: async (file?: Blob, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysPos/import`;
// 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 localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
const localVarFormParams = new FormData();
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
if (file !== undefined) {
localVarFormParams.append('file', file as any);
}
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = localVarFormParams;
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
@ -311,6 +456,47 @@ export const SysPosApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysPosDownloadTemplatePost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultIActionResult>>> {
const localVarAxiosArgs = await SysPosApiAxiosParamCreator(configuration).apiSysPosDownloadTemplatePost(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {PosInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysPosExportPost(body?: PosInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultIActionResult>>> {
const localVarAxiosArgs = await SysPosApiAxiosParamCreator(configuration).apiSysPosExportPost(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {Blob} [file]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysPosImportPostForm(file?: Blob, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysPosApiAxiosParamCreator(configuration).apiSysPosImportPostForm(file, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
@ -383,6 +569,35 @@ export const SysPosApiFactory = function (configuration?: Configuration, basePat
async apiSysPosDeletePost(body?: DeletePosInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysPosApiFp(configuration).apiSysPosDeletePost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysPosDownloadTemplatePost(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultIActionResult>> {
return SysPosApiFp(configuration).apiSysPosDownloadTemplatePost(options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {PosInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysPosExportPost(body?: PosInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultIActionResult>> {
return SysPosApiFp(configuration).apiSysPosExportPost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {Blob} [file]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysPosImportPostForm(file?: Blob, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysPosApiFp(configuration).apiSysPosImportPostForm(file, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
@ -446,6 +661,38 @@ export class SysPosApi extends BaseAPI {
public async apiSysPosDeletePost(body?: DeletePosInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysPosApiFp(this.configuration).apiSysPosDeletePost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysPosApi
*/
public async apiSysPosDownloadTemplatePost(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultIActionResult>> {
return SysPosApiFp(this.configuration).apiSysPosDownloadTemplatePost(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {PosInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysPosApi
*/
public async apiSysPosExportPost(body?: PosInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultIActionResult>> {
return SysPosApiFp(this.configuration).apiSysPosExportPost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {Blob} [file]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysPosApi
*/
public async apiSysPosImportPostForm(file?: Blob, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysPosApiFp(this.configuration).apiSysPosImportPostForm(file, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖

View File

@ -379,6 +379,7 @@ export * from './page-vis-log-input';
export * from './parameter-attributes';
export * from './parameter-info';
export * from './platform-type-enum';
export * from './pos-input';
export * from './pos-output';
export * from './print-type-enum';
export * from './promotion';
@ -493,6 +494,7 @@ export * from './sys-oauth-user';
export * from './sys-online-user';
export * from './sys-org';
export * from './sys-plugin';
export * from './sys-pos-import-body';
export * from './sys-print';
export * from './sys-region';
export * from './sys-report-data-source';

View File

@ -0,0 +1,38 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
*
* @export
* @interface PosInput
*/
export interface PosInput {
/**
*
*
* @type {string}
* @memberof PosInput
*/
name?: string | null;
/**
*
*
* @type {string}
* @memberof PosInput
*/
code?: string | null;
}

View File

@ -0,0 +1,28 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
*
* @export
* @interface SysPosImportBody
*/
export interface SysPosImportBody {
/**
* @type {Blob}
* @memberof SysPosImportBody
*/
file: Blob;
}

View File

@ -66,10 +66,13 @@ export default {
: 'Update Log',
: 'WeChat Payment',
API: 'Super API',
: 'Help Doc',
: 'Report',
: 'Data Source Configuration',
: 'Report configuration',
: 'Help',
: 'Framework Tutorial',
SqlSugar: 'SqlSugar',
: 'About Project',
: 'About',
AI对话: 'AI Dialog',
},
};

View File

@ -66,6 +66,9 @@ export default {
: '更新日志',
: '微信支付',
API: '超级API',
: '报表开发',
: '数据源配置',
: '报表配置',
: '帮助文档',
: '框架教程',
SqlSugar: 'SqlSugar',

View File

@ -7,7 +7,7 @@ export default {
button: 'Button',
query: 'Query',
reset: 'Reset',
view: 'view',
view: 'View',
add: 'Add',
allExpand: 'Expand All',
allFold: 'Collapse All',
@ -142,6 +142,7 @@ export default {
export: 'Export',
dataImport: 'Data Import',
template: 'Template',
downloadTemplate: 'DownloadTemplate',
import: 'Import',
downloadError: 'Download Error',
required: 'Required',

View File

@ -142,6 +142,7 @@ export default {
export: '导出',
dataImport: '数据导入',
template: '模板',
downloadTemplate: '下载模板',
import: '导入',
downloadError: '下载错误',
required: '不能为空',

View File

@ -4,12 +4,12 @@
<el-form :model="state.queryParams" ref="queryForm" :show-message="false" :inlineMessage="true" label-width="auto" style="flex: 1 1 0%">
<el-row :gutter="10">
<el-col class="mb5" :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="职位名称" prop="name">
<el-form-item :label="$t('message.list.jobTitle')">
<el-input v-model="state.queryParams.name" :placeholder="$t('message.list.jobTitle')" clearable @keyup.enter.native="handleQuery(true)" />
</el-form-item>
</el-col>
<el-col class="mb5" :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="职位编码" prop="code">
<el-form-item :label="$t('message.list.positionCode')">
<el-input v-model="state.queryParams.code" :placeholder="$t('message.list.positionCode')" clearable @keyup.enter.native="handleQuery(true)" />
</el-form-item>
</el-col>
@ -32,6 +32,11 @@
<vxe-grid ref="xGrid" class="xGrid-style" v-bind="options" v-on="gridEvents">
<template #toolbar_buttons>
<el-button type="primary" icon="ele-Plus" @click="handleAdd" v-auth="'sysPos/add'"> {{ $t('message.list.add') }} </el-button>
<el-button-group type="primary" style="padding-left: 12px">
<el-button plain icon="ele-Upload" @click="importData" v-auth="'sysPos/import'"> {{ $t('message.list.import') }} </el-button>
<el-button plain icon="ele-Download" @click="exportData" v-auth="'sysPos/export'"> {{ $t('message.list.export') }} </el-button>
<el-button plain icon="ele-FolderOpened" @click="downloadTemplate"> {{ $t('message.list.downloadTemplate') }} </el-button>
</el-button-group>
</template>
<template #toolbar_tools> </template>
<template #empty>
@ -69,10 +74,37 @@
</vxe-grid>
</el-card>
<el-dialog v-model="state.uploadVisible" :lock-scroll="false" draggable width="400px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-UploadFilled /> </el-icon>
<span> {{ $t('message.list.import') }} </span>
</div>
</template>
<div>
<el-upload ref="uploadRef" drag :auto-upload="false" :limit="1" :file-list="state.fileList" action="" :on-change="handleChange" accept=".xlsx">
<el-icon class="el-icon--upload">
<ele-UploadFilled />
</el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">请上传大小不超过 10MB 的文件</div>
</template>
</el-upload>
</div>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="state.uploadVisible = false">{{ $t('message.list.cancelButtonText') }}</el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @click="uploadFile">{{ $t('message.list.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
<EditPos ref="editPosRef" :title="state.title" @handleQuery="handleQuery" />
</div>
</template>
<!-- 职位管理 -->
<script lang="ts" setup name="sysPos">
import { onMounted, reactive, ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
@ -81,6 +113,7 @@ import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { Local } from '/@/utils/storage';
import { useI18n } from 'vue-i18n';
import { auth } from '/@/utils/authFunction';
import { downloadByData, getFileName } from '/@/utils/download';
import EditPos from '/@/views/system/pos/component/editPos.vue';
import ModifyRecord from '/@/components/table/modifyRecord.vue';
@ -103,6 +136,8 @@ const state = reactive({
},
visible: false,
title: '',
uploadVisible: false,
fileList: [] as any,
});
//
@ -143,7 +178,7 @@ onMounted(() => {
state.localPageParam = Local.get(localPageParamKey) || state.localPageParam;
});
// api
// api
const handleQueryApi = async (page: VxeGridPropTypes.ProxyAjaxQueryPageParams, sort: VxeGridPropTypes.ProxyAjaxQuerySortCheckedParams) => {
const params = Object.assign(state.queryParams, { page: page.currentPage, pageSize: page.pageSize, field: sort.field, order: sort.order, descStr: 'desc' }) as PagePosInput;
return getAPI(SysPosApi).apiSysPosPagePost(params);
@ -189,7 +224,7 @@ const openCopyMenu = (row: any) => {
editPosRef.value?.openDialog(copyRow);
};
//
//
const handleDelete = (row: any) => {
ElMessageBox.confirm(i18n.t('message.list.confirmDeletePosition', { name: row.name }), i18n.t('message.list.hint'), {
confirmButtonText: i18n.t('message.list.confirmButtonText'),
@ -221,4 +256,44 @@ const gridEvents: VxeGridListeners<PagePosOutput> = {
if (auth('sysPos/update')) await handleEdit(row);
},
};
// onChanne
const handleChange = (file: any, fileList: []) => {
state.fileList = fileList;
};
//
const uploadFile = async () => {
if (state.fileList.length < 1) return;
state.uploadVisible = false;
options.loading = true;
await getAPI(SysPosApi).apiSysPosImportPostForm(state.fileList[0].raw);
handleQuery();
ElMessage.success('上传成功');
options.loading = false;
};
//
const importData = () => {
state.uploadVisible = true;
};
//
const exportData = async () => {
options.loading = true;
var res = await getAPI(SysPosApi).apiSysPosExportPost(state.queryParams, { responseType: 'blob' });
options.loading = false;
var fileName = getFileName(res.headers);
downloadByData(res.data as any, fileName);
};
//
const downloadTemplate = async () => {
var res = await getAPI(SysPosApi).apiSysPosDownloadTemplatePost({ responseType: 'blob' });
var fileName = getFileName(res.headers);
downloadByData(res.data as any, fileName);
};
</script>