refalactor:国际化前端

This commit is contained in:
PZ688 2025-02-28 18:19:00 +08:00
parent f4f1c5c4e6
commit 04951cefbd
5 changed files with 60 additions and 44 deletions

View File

@ -4,18 +4,18 @@
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-UploadFilled /> </el-icon>
<span> 数据导入 </span>
<span> {{ t('list.dataImport') }} </span>
</div>
</template>
<el-row :gutter="15" v-loading="state.loading">
<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
<el-button class="ml10" type="info" icon="ele-Download" v-reclick="3000" @click="() => download()" :disabled="state.loading">模板</el-button>
<el-button class="ml10" type="info" icon="ele-Download" v-reclick="3000" @click="() => download()" :disabled="state.loading">{{ t('list.template') }}</el-button>
</el-col>
<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
<el-upload :limit="1" :show-file-list="false" :on-exceed="handleExceed" :http-request="handleImportData" ref="uploadRef">
<template #trigger>
<el-button type="primary" icon="ele-MostlyCloudy" v-reclick="3000" :disabled="state.loading">导入</el-button>
<el-button type="primary" icon="ele-MostlyCloudy" v-reclick="3000" :disabled="state.loading">{{ t('list.import') }}</el-button>
</template>
</el-upload>
</el-col>
@ -23,7 +23,7 @@
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @click="() => (state.isShowDialog = false)" :disabled="state.loading"> </el-button>
<el-button icon="ele-CircleCloseFilled" @click="() => (state.isShowDialog = false)" :disabled="state.loading">{{ t('list.cancelButtonText') }}</el-button>
</span>
</template>
</el-dialog>
@ -35,7 +35,9 @@ import type { UploadInstance, UploadProps, UploadRawFile, UploadRequestOptions }
import { ElUpload, ElMessage, genFileId } from 'element-plus';
import { downloadStreamFile } from '/@/utils/download';
import { reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const uploadRef = ref<UploadInstance>();
const state = reactive({
isShowDialog: false,
@ -80,7 +82,7 @@ const download = () => {
props
.download()
.then((res: any) => downloadStreamFile(res))
.catch((res: any) => ElMessage.error('下载错误: ' + res));
.catch((res: any) => ElMessage.error(`${t('list.downloadError')}: ${res}`));
};
//

View File

@ -5,7 +5,7 @@
<slot name="command"></slot>
</div>
<div v-loading="state.exportLoading" class="table-footer-tool">
<SvgIcon v-if="!config.hideRefresh" name="iconfont icon-shuaxin" :size="22" title="刷新" @click="onRefreshTable" />
<SvgIcon v-if="!config.hideRefresh" name="iconfont icon-shuaxin" :size="22" :title="t('message.list.refresh')" @click="onRefreshTable" />
<el-tooltip effect="light" :content="state.switchFixedContent" placement="bottom-start" :show-after="200" v-if="state.haveFixed">
<el-icon :style="{ color: state.fixedIconColor }" @click="switchFixed"><ele-Switch /></el-icon>
</el-tooltip>
@ -13,24 +13,24 @@
<SvgIcon name="iconfont icon-yunxiazai_o" :size="22" title="导出" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="onExportTable">导出本页数据</el-dropdown-item>
<el-dropdown-item @click="onExportTableAll">导出全部数据</el-dropdown-item>
<el-dropdown-item @click="onExportTable">{{ t('message.list.exportCurrentPage') }}</el-dropdown-item>
<el-dropdown-item @click="onExportTableAll">{{ t('message.list.exportAll') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<SvgIcon v-if="!config.hidePrint" name="iconfont icon-dayin" :size="19" title="打印" @click="onPrintTable" />
<SvgIcon v-if="!config.hidePrint" name="iconfont icon-dayin" :size="19" :title="t('message.list.print')" @click="onPrintTable" />
<el-popover v-if="!config.hideSet" placement="bottom-end" trigger="click" transition="el-zoom-in-top" popper-class="table-tool-popper" :width="300" :persistent="false" @show="onSetTable">
<template #reference>
<SvgIcon name="iconfont icon-quanjushezhi_o" :size="22" title="设置" />
<SvgIcon name="iconfont icon-quanjushezhi_o" :size="22" :title="t('message.list.settings')" />
</template>
<template #default>
<div class="tool-box">
<el-tooltip content="拖动进行排序" placement="top-start">
<el-tooltip :content="t('message.list.dragToSort')" placement="top-start">
<SvgIcon name="fa fa-question-circle-o" :size="17" class="ml11" color="#909399" />
</el-tooltip>
<el-checkbox v-model="state.checkListAll" :indeterminate="state.checkListIndeterminate" class="ml10 mr1" label="列显示" @change="onCheckAllChange" />
<el-checkbox v-model="getConfig.isSerialNo" class="ml12 mr1" label="序号" />
<el-checkbox v-if="getConfig.showSelection" v-model="getConfig.isSelection" class="ml12 mr1" label="多选" />
<el-checkbox v-model="state.checkListAll" :indeterminate="state.checkListIndeterminate" class="ml10 mr1" :label="t('message.list.columnDisplay')" @change="onCheckAllChange" />
<el-checkbox v-model="getConfig.isSerialNo" class="ml12 mr1" :label="t('message.list.seq')" />
<el-checkbox v-if="getConfig.showSelection" v-model="getConfig.isSelection" class="ml12 mr1" :label="t('message.list.multiSelect')" />
</div>
<el-scrollbar>
<div ref="toolSetRef" class="tool-sortable">
@ -110,7 +110,7 @@
</el-table-column>
</el-table-column>
<template #empty>
<el-empty description="暂无数据" />
<el-empty :description="t('message.list.noData')" />
</template>
</el-table>
<div v-if="!config.hidePagination && state.showPagination" class="table-footer mt15">
@ -141,6 +141,7 @@ import { exportExcel } from '/@/utils/exportExcel';
// import '/@/theme/tableTool.scss';
import printJs from 'print-js';
import formatter from '/@/components/table/formatter.vue';
import { useI18n } from 'vue-i18n';
//
const props = defineProps({
@ -188,6 +189,7 @@ const toolSetRef = ref();
const tableRef = ref();
const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig);
const { t } = useI18n();
const state = reactive({
data: [] as Array<EmptyObjectType>,
loading: false,
@ -208,7 +210,7 @@ const state = reactive({
haveFixed: false,
currentFixed: false,
serialNoFixed: false,
switchFixedContent: '取消固定列',
switchFixedContent: t('message.list.unfixColumn'),
fixedIconColor: themeConfig.value.primary,
});
@ -284,12 +286,12 @@ const pageReset = () => {
};
//
const onExportTable = () => {
if (setHeader.value.length <= 0) return ElMessage.error('没有勾选要导出的列');
if (setHeader.value.length <= 0) return ElMessage.error(t('message.list.noSelectedColumns'));
exportData(state.data);
};
//
const onExportTableAll = async () => {
if (setHeader.value.length <= 0) return ElMessage.error('没有勾选要导出的列');
if (setHeader.value.length <= 0) return ElMessage.error(t('message.list.noSelectedColumns'));
state.exportLoading = true;
const param = Object.assign({}, props.param, { page: 1, pageSize: 9999999 });
const res = await props.getData(param);
@ -299,7 +301,7 @@ const onExportTableAll = async () => {
};
//
const exportData = (data: Array<EmptyObjectType>) => {
if (data.length <= 0) return ElMessage.error('没有数据可以导出');
if (data.length <= 0) return ElMessage.error(t('message.list.noDataToExport'));
state.exportLoading = true;
let exportData = JSON.parse(JSON.stringify(data));
if (props.exportChangeData) {
@ -311,7 +313,7 @@ const exportData = (data: Array<EmptyObjectType>) => {
setHeader.value.filter((item) => {
return item.type != 'action';
}),
'导出数据'
t('message.list.exportData')
);
state.exportLoading = false;
};
@ -434,7 +436,7 @@ const clearFixed = () => {
const switchFixed = () => {
state.currentFixed = !state.currentFixed;
state.switchFixedContent = state.currentFixed ? '取消固定列' : '启用固定列';
state.switchFixedContent = state.currentFixed ? t('message.list.unfixColumn') : t('message.list.fixColumn');
if (state.currentFixed) {
state.fixedIconColor = themeConfig.value.primary;
state.columns = JSON.parse(JSON.stringify(state.oldColumns));

View File

@ -2,55 +2,58 @@
<el-popover placement="bottom" width="300" trigger="hover">
<template #reference>
<el-text type="primary" class="cursor-default">
<el-icon><ele-InfoFilled /></el-icon>
<el-icon><ele-InfoFilled /></el-icon>{{ t('message.list.detail') }}
</el-text>
</template>
<el-descriptions direction="vertical" :column="2" border>
<el-descriptions-item width="140">
<template #label>
<el-text>
<el-icon><ele-UserFilled /></el-icon>
<el-icon><ele-UserFilled /></el-icon>{{ t('message.list.creator') }}
</el-text>
</template>
<el-tag>{{ props.data.createUserName ?? '无' }}</el-tag>
<el-tag>{{ props.data.createUserName ?? t('message.list.none') }}</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<el-text>
<el-icon><ele-Calendar /></el-icon>
<el-icon><ele-Calendar /></el-icon>{{ t('message.list.createTime') }}
</el-text>
</template>
<el-tag>{{ props.data.createTime ?? '无' }}</el-tag>
<el-tag>{{ props.data.createTime ?? t('message.list.none') }}</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<el-text>
<el-icon><ele-UserFilled /></el-icon>
<el-icon><ele-UserFilled /></el-icon>{{ t('message.list.modifier') }}
</el-text>
</template>
<el-tag>{{ props.data.updateUserName ?? '无' }}</el-tag>
<el-tag>{{ props.data.updateUserName ?? t('message.list.none') }}</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<el-text>
<el-icon><ele-Calendar /></el-icon>
<el-icon><ele-Calendar /></el-icon>{{ t('message.list.modifyTime') }}
</el-text>
</template>
<el-tag>{{ props.data.updateTime ?? '无' }}</el-tag>
<el-tag>{{ props.data.updateTime ?? t('message.list.none') }}</el-tag>
</el-descriptions-item>
<el-descriptions-item v-if="'remark' in props.data">
<template #label>
<el-text>
<el-icon><ele-Tickets /></el-icon>
<el-icon><ele-Tickets /></el-icon>{{ t('message.list.remark') }}
</el-text>
</template>
{{ props.data.remark ?? '无' }}
{{ props.data.remark ?? t('message.list.none') }}
</el-descriptions-item>
</el-descriptions>
</el-popover>
</template>
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps<{
data: ModifyRecord;
}>();

View File

@ -9,7 +9,7 @@
label-width="auto"
:label="val.label"
:prop="val.prop"
:rules="[{ required: val.required, message: `${val.label}不能为空`, trigger: val.type === 'input' ? 'blur' : 'change' }]"
:rules="[{ required: val.required, message: `${val.label}${t('message.list.required')}`, trigger: val.type === 'input' ? 'blur' : 'change' }]"
>
<el-input
v-model="state.innerModelValue[val.prop]"
@ -47,9 +47,9 @@
v-bind="val.comProps"
type="daterange"
value-format="YYYY/MM/DD"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
:range-separator="t('message.list.to')"
:start-placeholder="t('message.list.startDate')"
:end-placeholder="t('message.list.endDate')"
:clearable="!val.required"
:shortcuts="shortcuts"
:default-time="defaultTime"
@ -89,8 +89,8 @@
<div>
<!-- 使用el-button-group会导致具有type属性的按钮的右边框无法显示 -->
<!-- <el-button-group> -->
<el-button plain type="primary" icon="ele-Search" @click="onSearch(tableSearchRef)"> 查询 </el-button>
<el-button icon="ele-Refresh" @click="onReset(tableSearchRef)" style="margin-left: 12px"> 重置 </el-button>
<el-button plain type="primary" icon="ele-Search" @click="onSearch(tableSearchRef)"> {{ t('message.list.query') }} </el-button>
<el-button icon="ele-Refresh" @click="onReset(tableSearchRef)" style="margin-left: 12px"> {{ t('message.list.reset') }} </el-button>
<!-- </el-button-group> -->
</div>
</el-form-item>
@ -107,6 +107,9 @@
import { reactive, ref, watch } from 'vue';
import type { FormInstance } from 'element-plus';
import { dayjs } from 'element-plus';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
//
const props = defineProps({
@ -174,7 +177,7 @@ const defaultTime = ref<[Date, Date]>([new Date(2000, 1, 1, 0, 0, 0), new Date(2
/** 时间范围快捷选择 */
const shortcuts = [
{
text: '7天内',
text: t('message.list.last7Days'),
value: () => {
const end = dayjs().endOf('day').toDate();
const start = dayjs().startOf('day').add(-7, 'day').toDate();
@ -182,7 +185,7 @@ const shortcuts = [
},
},
{
text: '1个月内',
text: t('message.list.lastMonth'),
value: () => {
const end = dayjs().endOf('day').toDate();
const start = dayjs().startOf('day').add(-1, 'month').toDate();
@ -190,7 +193,7 @@ const shortcuts = [
},
},
{
text: '3个月内',
text: t('message.list.last3Months'),
value: () => {
const end = dayjs().endOf('day').toDate();
const start = dayjs().startOf('day').add(-3, 'month').toDate();

View File

@ -6,10 +6,11 @@
<th v-for="(citem, ci) in $props.columns" :key="ci" v-show="citem.ifShow == undefined ? true : citem.ifShow" style="text-align: center">
{{ citem.label }}
</th>
<th style="text-align: center" v-show="!$props.disabled">操作</th>
<th style="text-align: center" v-show="!$props.disabled">{{ t('message.list.operation') }}</th>
</tr>
</thead>
<tbody class="el-table-tbody">
<tr v-for="(item, index) in vm.value" :key="index">
<td v-for="(citem, ci) in $props.columns" :key="ci" style="text-align: center" v-show="citem.ifShow == undefined ? true : citem.ifShow">
<component v-if="citem.component != 'el-select'" :is="citem.component" v-model="item[citem.field]" v-bind="renderComponentProp(citem)" :disabled="$props.disabled" />
@ -18,10 +19,11 @@
</el-select>
</td>
<td style="text-align: center" v-show="!$props.disabled">
<el-button type="danger" @click="del(item, index)">删除</el-button>
<el-button type="danger" @click="del(item, index)">{{ t('message.list.delete') }}</el-button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td v-for="(citem, ci) in $props.columns" :key="ci" style="text-align: center" v-show="citem.ifShow == undefined ? true : citem.ifShow">
@ -31,10 +33,11 @@
</el-select>
</td>
<td class="el-table-cell el-table-cell-ellipsis" style="text-align: center" v-show="!$props.disabled">
<el-button type="primary" @click="add">添加</el-button>
<el-button type="primary" @click="add">{{ t('message.list.add') }}</el-button>
</td>
</tr>
</tfoot>
</table>
</div>
</template>
@ -44,6 +47,9 @@ import { reactive } from 'vue';
import { ElMessage, dayjs } from 'element-plus';
import AsyncValidator from 'async-validator';
import { isDate, isString } from 'lodash-es';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
value: {