feat: i18n,add en and zh-cn language.

This commit is contained in:
ex_zhangwenlei@exiot.cmcc
2024-11-22 14:53:36 +08:00
parent 8e6eff54f4
commit 391142223f
18 changed files with 189 additions and 116 deletions

View File

@@ -10,7 +10,7 @@ import 'vue3-colorpicker/style.css';
import { isRgbOrRgba, isHex } from '@/utils/color'
import PatternSetting from './components/PatternSetting.vue'
import {languageList} from '@/locales/i18n'
import {Language} from '@/locales/i18n'
import i18n from '@/locales/i18n'
const globalConfig = useStore().globalConfig
const personConfig = useStore().personConfig
const prizeConfig= useStore().prizeConfig
@@ -44,11 +44,11 @@ const formErr = ref({
const schema = zod.object({
rowCount: zod.number({
required_error: '必填项',
invalid_type_error: '必须填入数字',
required_error: i18n.global.t('error.require'),
invalid_type_error: i18n.global.t('error.requireNumber'),
})
.min(1, '最小为1')
.max(100, '最大为100')
.min(1, i18n.global.t('error.minNumber1'))
.max(100, i18n.global.t('error.maxNumber100'))
// 格式化
@@ -169,7 +169,7 @@ onMounted(() => {
</div>
</dialog>
<div>
<h2>全局配置</h2>
<h2>{{$t('viewTitle.globalSetting')}}</h2>
<div class="mb-8">
<button class="btn btn-sm btn-primary" @click="resetDataDialogRef.showModal()">{{$t('button.resetAllData')}}</button>
</div>
@@ -178,7 +178,7 @@ onMounted(() => {
<div class="label">
<span class="label-text">{{$t('table.title')}}</span>
</div>
<input type="text" v-model="topTitleValue" placeholder="输入标题"
<input type="text" v-model="topTitleValue" :placeholder="$t('placeHolder.enterTitle')"
class="w-full max-w-xs input input-bordered" />
</div>
</label>

View File

@@ -69,13 +69,13 @@ watch(() => imgUploadToast.value, (val) => {
<template>
<div class="toast toast-top toast-end">
<div class="alert alert-error" v-if="imgUploadToast == 2">
<span>上传失败</span>
<span>{{ $t('error.uploadFail') }}</span>
</div>
<div class="alert alert-success" v-if="imgUploadToast == 1">
<span>上传成功</span>
<span>{{ $t('error.uploadSuccess') }}</span>
</div>
<div class="alert alert-error" v-if="imgUploadToast == 3">
<span>不是图片</span>
<span>{{ $t('error.notImage') }}</span>
</div>
</div>

View File

@@ -8,7 +8,7 @@ import * as XLSX from 'xlsx'
import { readFileBinary } from '@/utils/file'
import { addOtherInfo } from '@/utils'
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
import i18n from '@/locales/i18n'
const personConfig = useStore().personConfig
const { getAllPersonList: allPersonList, getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
const limitType = '.xlsx,.xls'
@@ -38,9 +38,9 @@ const exportData = () => {
delete data[i].prizeId
// 修改字段名称
if (data[i].isWin) {
data[i].isWin = '是'
data[i].isWin = i18n.global.t('data.yes')
} else {
data[i].isWin = '否'
data[i].isWin = i18n.global.t('data.no')
}
// 格式化数组为
data[i].prizeTime = data[i].prizeTime.join(',')
@@ -48,13 +48,13 @@ const exportData = () => {
}
let dataString = JSON.stringify(data)
dataString = dataString
.replaceAll(/uid/g, '编号')
.replaceAll(/isWin/g, '是否中奖')
.replaceAll(/department/g, '部门')
.replaceAll(/name/g, '姓名')
.replaceAll(/identity/g, '身份')
.replaceAll(/prizeName/g, '获奖')
.replaceAll(/prizeTime/g, '获奖时间')
.replaceAll(/uid/g, i18n.global.t('data.number'))
.replaceAll(/isWin/g, i18n.global.t('data.isWin'))
.replaceAll(/department/g, i18n.global.t('data.department'))
.replaceAll(/name/g, i18n.global.t('data.name'))
.replaceAll(/identity/g, i18n.global.t('data.identity'))
.replaceAll(/prizeName/g, i18n.global.t('data.prizeName'))
.replaceAll(/prizeTime/g, i18n.global.t('data.prizeTime'))
data = JSON.parse(dataString)
@@ -80,30 +80,30 @@ const delPersonItem = (row: IPersonConfig) => {
const tableColumns = [
{
label: '编号',
label: i18n.global.t('data.number'),
props: 'uid',
},
{
label: '姓名',
label: i18n.global.t('data.name'),
props: 'name',
},
{
label: '部门',
label: i18n.global.t('data.department'),
props: 'department',
},
{
label: '身份',
label: i18n.global.t('data.identity'),
props: 'identity',
},
{
label: '是否已中奖',
label: i18n.global.t('data.isWin'),
props: 'isWin',
formatValue(row: IPersonConfig) {
return row.isWin ? '是' : '否'
return row.isWin ? i18n.global.t('data.yes') : i18n.global.t('data.no')
}
},
{
label: '操作',
label: i18n.global.t('data.operation'),
actions: [
// {
// label: '编辑',
@@ -113,7 +113,7 @@ const tableColumns = [
// }
// },
{
label: '删除',
label: i18n.global.t('data.delete'),
type: 'btn-error',
onClick: (row: IPersonConfig) => {
delPersonItem(row)
@@ -156,12 +156,12 @@ onMounted(() => {
</dialog>
<div class="min-w-1000px">
<h2>人员管理</h2>
<h2>{{ $t('viewTitle.personManagement') }}</h2>
<div class="flex gap-3">
<button class="btn btn-error btn-sm" @click="delAllDataDialog.showModal()">{{ $t('button.allDelete') }}</button>
<div class="tooltip tooltip-bottom" :data-tip="$t('tooltip.downloadTemplateTip')">
<a class="no-underline btn btn-secondary btn-sm" download="人口登记表.xlsx" target="_blank"
href="/log-lottery/人口登记表.xlsx">{{ $t('button.downloadTemplate') }}</a>
<a class="no-underline btn btn-secondary btn-sm" :download="$t('data.xlsxName')" target="_blank"
:href="'/log-lottery/'+$t('data.xlsxName')">{{ $t('button.downloadTemplate') }}</a>
</div>
<div class="">
<label for="explore">
@@ -173,8 +173,6 @@ onMounted(() => {
<span class="btn btn-primary btn-sm">{{ $t('button.importData') }}</span>
</div>
</label>
<!-- <button class="btn btn-primary btn-sm">上传excel</button> -->
</div>
<button class="btn btn-error btn-sm" @click="resetDataDialog.showModal()">{{ $t('button.resetData') }}</button>
<button class="btn btn-accent btn-sm" @click="exportData">{{ $t('button.exportResult') }}</button>

View File

@@ -5,7 +5,7 @@ import useStore from '@/store'
import { IPersonConfig } from '@/types/storeType';
import { storeToRefs } from 'pinia';
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
import i18n from '@/locales/i18n'
const personConfig = useStore().personConfig
const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: alreadyPersonDetail } = storeToRefs(personConfig)
@@ -25,32 +25,32 @@ const handleMoveNotPerson = (row: IPersonConfig) => {
const tableColumnsList = [
{
label: '编号',
label: i18n.global.t('data.number'),
props: 'uid',
sort: true
},
{
label: '姓名',
label: i18n.global.t('data.number'),
props: 'name',
},
{
label: '部门',
label: i18n.global.t('data.department'),
props: 'department',
},
{
label: '身份',
label: i18n.global.t('data.identity'),
props: 'identity',
},
{
label: '奖品',
label: i18n.global.t('data.prizeName'),
props: 'prizeName',
sort: true
},
{
label: '操作',
label: i18n.global.t('data.operation'),
actions: [
{
label: '移入未中奖名单',
label: i18n.global.t('data.removePerson'),
type: 'btn-info',
onClick: (row: IPersonConfig) => {
handleMoveNotPerson(row)
@@ -61,37 +61,37 @@ const tableColumnsList = [
]
const tableColumnsDetail = [
{
label: '编号',
label: i18n.global.t('data.number'),
props: 'uid',
sort: true
},
{
label: '姓名',
label: i18n.global.t('data.number'),
props: 'name',
},
{
label: '部门',
label: i18n.global.t('data.department'),
props: 'department',
},
{
label: '身份',
label: i18n.global.t('data.identity'),
props: 'identity',
},
{
label: '奖品',
label: i18n.global.t('data.prizeName'),
props: 'prizeName',
sort: true
},
{
label: '中奖时间',
label: i18n.global.t('data.prizeTime'),
props: 'prizeTime',
},
{
label: '操作',
label: i18n.global.t('data.operation'),
actions: [
{
label: '移入未中奖名单',
label: i18n.global.t('data.removePerson'),
type: 'btn-info',
onClick: (row: IPersonConfig) => {
handleMoveNotPerson(row)
@@ -108,7 +108,6 @@ const tableColumnsDetail = [
<h2>{{ $t('viewTitle.winnerManagement') }}</h2>
<div class="flex items-center justify-start gap-10">
<!-- <button class="btn btn-error btn-sm" @click="deleteAll">全部删除</button> -->
<div>
<span>{{$t('table.luckyPeopleNumber')}}</span>
<span>{{ alreadyPersonList.length }}</span>

View File

@@ -5,7 +5,7 @@ import { IPrizeConfig } from '@/types/storeType'
import { storeToRefs } from 'pinia'
import localforage from 'localforage'
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
import i18n from '@/locales/i18n'
const imageDbStore = localforage.createInstance({
name: 'imgStore'
})
@@ -22,7 +22,7 @@ const selectedPrize = ref<IPrizeConfig | null>()
const addPrize = () => {
const defaultPrizeCOnfig: IPrizeConfig = {
id: new Date().getTime().toString(),
name: '奖项',
name: i18n.global.t('data.prizeName'),
sort: 0,
isAll: false,
count: 1,
@@ -178,7 +178,7 @@ watch(() => prizeList.value, (val: IPrizeConfig[]) => {
<div class="label">
<span class="label-text">{{ $t('table.prizeName') }}</span>
</div>
<input type="text" v-model="item.name" placeholder="名称"
<input type="text" v-model="item.name" :placeholder="$t('placeHolder.name')"
class="w-full max-w-xs input-sm input input-bordered" />
</label>
<label class="w-1/2 max-w-xs mb-10 form-control">
@@ -192,19 +192,12 @@ watch(() => prizeList.value, (val: IPrizeConfig[]) => {
<div class="label">
<span class="label-text">{{ $t('table.numberParticipants') }}</span>
</div>
<input type="number" v-model="item.count" placeholder="获奖人数" @change="changePrizePerson(item)"
<input type="number" v-model="item.count" :placeholder="$t('placeHolder.winnerCount')" @change="changePrizePerson(item)"
class="w-full max-w-xs p-0 m-0 input-sm input input-bordered" />
<div class="tooltip tooltip-bottom" :data-tip="$t('table.isDone') + item.isUsedCount + '/' + item.count">
<progress class="w-full progress" :value="item.isUsedCount" :max="item.count"></progress>
</div>
</label>
<!-- <label class="w-1/2 max-w-xs mb-10 form-control">
<div class="label">
<span class="label-text">已获奖人数</span>
</div>
<input disabled type="number" v-model="item.isUsedCount" placeholder="获奖人数"
class="w-full max-w-xs input-sm input input-bordered" />
</label> -->
<label class="w-1/2 max-w-xs mb-10 form-control">
<div class="label">
<span class="label-text">{{ $t('table.isDone') }}</span>
@@ -218,7 +211,7 @@ watch(() => prizeList.value, (val: IPrizeConfig[]) => {
</div>
<select class="w-full max-w-xs select select-warning select-sm" v-model="item.picture">
<option v-if="item.picture.id" :value="{ id: '', name: '', url: '' }"><span></span></option>
<option disabled selected>选择一张图片</option>
<option disabled selected>{{ $t('table.selectPicture') }}</option>
<option v-for="picItem in localImageList" :key="picItem.id" :value="picItem">{{ picItem.name }}
</option>
</select>
@@ -233,7 +226,7 @@ watch(() => prizeList.value, (val: IPrizeConfig[]) => {
<li class="relative flex items-center justify-center w-8 h-8 bg-slate-600/60 separated"
v-for="se in item.separateCount.countList" :key="se.id">
<div class="flex items-center justify-center w-full h-full tooltip"
:data-tip="'已抽取:' + se.isUsedCount + '/' + se.count">
:data-tip="$t('tooltip.doneCount') + se.isUsedCount + '/' + se.count">
<div class="absolute left-0 z-50 h-full bg-blue-300/80"
:style="`width:${se.isUsedCount * 100 / se.count}%`"></div>
<span>{{ se.count }}</span>

View File

@@ -1,10 +1,11 @@
<script setup lang='ts'>
import {ref,onMounted} from 'vue'
import markdownit from 'markdown-it'
import i18n from '@/locales/i18n'
const md = markdownit()
const readmeHtml=ref('')
const readMd=()=>{
fetch('/log-lottery/readme.md')
fetch('/log-lottery/'+i18n.global.t('data.readmeName'))
.then(res=>res.text())
.then(res=>{
readmeHtml.value = md.render(res)