feat: support i18n (#607)

* feat: support i18n

* feat: support i18n

* feat: support i18n

* feat: support i18n

* feat: support i18n

* feat: tag tabs i18n

* fix: fix missing i18n

* fix: fix missing i18n
This commit is contained in:
wū yāng 2023-10-03 13:48:35 +08:00 committed by GitHub
parent 565772bd27
commit 3affc4ddfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 2243 additions and 784 deletions

View File

@ -33,6 +33,7 @@
"tvision-color": "^1.6.0", "tvision-color": "^1.6.0",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
"vue-i18n": "^9.4.1",
"vue-router": "~4.2.4" "vue-router": "~4.2.4"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,9 +1,12 @@
<template> <template>
<router-view :class="[mode]" /> <t-config-provider :global-config="getComponentsLocale">
<router-view :key="locale" :class="[mode]"
/></t-config-provider>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'; import { computed } from 'vue';
import { useLocale } from '@/locales/useLocale';
import { useSettingStore } from '@/store'; import { useSettingStore } from '@/store';
const store = useSettingStore(); const store = useSettingStore();
@ -11,6 +14,8 @@ const store = useSettingStore();
const mode = computed(() => { const mode = computed(() => {
return store.displayMode; return store.displayMode;
}); });
const { getComponentsLocale, locale } = useLocale();
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
#nprogress .bar { #nprogress .bar {

View File

@ -2,7 +2,7 @@ import type { MenuListResult } from '@/api/model/permissionModel';
import { request } from '@/utils/request'; import { request } from '@/utils/request';
const Api = { const Api = {
MenuList: '/get-menu-list', MenuList: '/get-menu-list-i18n',
}; };
export function getMenuList() { export function getMenuList() {

View File

@ -5,45 +5,45 @@
<t-col :span="10"> <t-col :span="10">
<t-row :gutter="[24, 24]"> <t-row :gutter="[24, 24]">
<t-col :span="4"> <t-col :span="4">
<t-form-item label="合同名称" name="name"> <t-form-item :label="$t('components.commonTable.contractName')" name="name">
<t-input <t-input
v-model="formData.name" v-model="formData.name"
class="form-item-content" class="form-item-content"
type="search" type="search"
placeholder="请输入合同名称" :placeholder="$t('components.commonTable.contractNamePlaceholder')"
:style="{ minWidth: '134px' }" :style="{ minWidth: '134px' }"
/> />
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="4"> <t-col :span="4">
<t-form-item label="合同状态" name="status"> <t-form-item :label="$t('components.commonTable.contractStatus')" name="status">
<t-select <t-select
v-model="formData.status" v-model="formData.status"
class="form-item-content" class="form-item-content"
:options="CONTRACT_STATUS_OPTIONS" :options="CONTRACT_STATUS_OPTIONS"
placeholder="请选择合同状态" :placeholder="$t('components.commonTable.contractStatusPlaceholder')"
clearable clearable
/> />
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="4"> <t-col :span="4">
<t-form-item label="合同编号" name="no"> <t-form-item :label="$t('components.commonTable.contractNum')" name="no">
<t-input <t-input
v-model="formData.no" v-model="formData.no"
class="form-item-content" class="form-item-content"
placeholder="请输入合同编号" :placeholder="$t('components.commonTable.contractNumPlaceholder')"
:style="{ minWidth: '134px' }" :style="{ minWidth: '134px' }"
/> />
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="4"> <t-col :span="4">
<t-form-item label="合同类型" name="type"> <t-form-item :label="$t('components.commonTable.contractType')" name="type">
<t-select <t-select
v-model="formData.type" v-model="formData.type"
style="display: inline-block" style="display: inline-block"
class="form-item-content" class="form-item-content"
:options="CONTRACT_TYPE_OPTIONS" :options="CONTRACT_TYPE_OPTIONS"
placeholder="请选择合同类型" :placeholder="$t('components.commonTable.contractTypePlaceholder')"
clearable clearable
/> />
</t-form-item> </t-form-item>
@ -52,8 +52,10 @@
</t-col> </t-col>
<t-col :span="2" class="operation-container"> <t-col :span="2" class="operation-container">
<t-button theme="primary" type="submit" :style="{ marginLeft: 'var(--td-comp-margin-s)' }"> 查询 </t-button> <t-button theme="primary" type="submit" :style="{ marginLeft: 'var(--td-comp-margin-s)' }">
<t-button type="reset" variant="base" theme="default"> 重置 </t-button> {{ $t('components.commonTable.query') }}
</t-button>
<t-button type="reset" variant="base" theme="default"> {{ $t('components.commonTable.reset') }} </t-button>
</t-col> </t-col>
</t-row> </t-row>
</t-form> </t-form>
@ -72,29 +74,41 @@
@change="rehandleChange" @change="rehandleChange"
> >
<template #status="{ row }"> <template #status="{ row }">
<t-tag v-if="row.status === CONTRACT_STATUS.FAIL" theme="danger" variant="light"> 审核失败 </t-tag> <t-tag v-if="row.status === CONTRACT_STATUS.FAIL" theme="danger" variant="light">
<t-tag v-if="row.status === CONTRACT_STATUS.AUDIT_PENDING" theme="warning" variant="light"> 待审核 </t-tag> {{ $t('components.commonTable.contractStatusEnum.fail') }}
<t-tag v-if="row.status === CONTRACT_STATUS.EXEC_PENDING" theme="warning" variant="light"> 待履行 </t-tag> </t-tag>
<t-tag v-if="row.status === CONTRACT_STATUS.EXECUTING" theme="success" variant="light"> 履行中 </t-tag> <t-tag v-if="row.status === CONTRACT_STATUS.AUDIT_PENDING" theme="warning" variant="light">
<t-tag v-if="row.status === CONTRACT_STATUS.FINISH" theme="success" variant="light"> 已完成 </t-tag> {{ $t('components.commonTable.contractStatusEnum.audit') }}
</t-tag>
<t-tag v-if="row.status === CONTRACT_STATUS.EXEC_PENDING" theme="warning" variant="light">
{{ $t('components.commonTable.contractStatusEnum.pending') }}
</t-tag>
<t-tag v-if="row.status === CONTRACT_STATUS.EXECUTING" theme="success" variant="light">
{{ $t('components.commonTable.contractStatusEnum.executing') }}
</t-tag>
<t-tag v-if="row.status === CONTRACT_STATUS.FINISH" theme="success" variant="light">
{{ $t('components.commonTable.contractStatusEnum.finish') }}
</t-tag>
</template> </template>
<template #contractType="{ row }"> <template #contractType="{ row }">
<p v-if="row.contractType === CONTRACT_TYPES.MAIN">审核失败</p> <p v-if="row.contractType === CONTRACT_TYPES.MAIN">{{ $t('pages.listBase.contractStatusEnum.fail') }}</p>
<p v-if="row.contractType === CONTRACT_TYPES.SUB">待审核</p> <p v-if="row.contractType === CONTRACT_TYPES.SUB">{{ $t('pages.listBase.contractStatusEnum.audit') }}</p>
<p v-if="row.contractType === CONTRACT_TYPES.SUPPLEMENT">待履行</p> <p v-if="row.contractType === CONTRACT_TYPES.SUPPLEMENT">
{{ $t('pages.listBase.contractStatusEnum.pending') }}
</p>
</template> </template>
<template #paymentType="{ row }"> <template #paymentType="{ row }">
<p v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.PAYMENT" class="payment-col"> <div v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.PAYMENT" class="payment-col">
付款<trend class="dashboard-item-trend" type="up" /> {{ $t('pages.listBase.pay') }}<trend class="dashboard-item-trend" type="up" />
</p> </div>
<p v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.RECEIPT" class="payment-col"> <div v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.RECEIPT" class="payment-col">
收款<trend class="dashboard-item-trend" type="down" /> {{ $t('pages.listBase.receive') }}<trend class="dashboard-item-trend" type="down" />
</p> </div>
</template> </template>
<template #op="slotProps"> <template #op="slotProps">
<t-space> <t-space>
<t-link theme="primary" @click="rehandleClickOp(slotProps)">管理</t-link> <t-link theme="primary" @click="handleClickDetail()"> {{ $t('pages.listBase.detail') }}</t-link>
<t-link theme="danger" @click="handleClickDelete(slotProps)">删除</t-link> <t-link theme="danger" @click="handleClickDelete(slotProps)"> {{ $t('pages.listBase.delete') }}</t-link>
</t-space> </t-space>
</template> </template>
</t-table> </t-table>
@ -111,17 +125,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { MessagePlugin, PageInfo, PrimaryTableCol, TableRowData } from 'tdesign-vue-next'; import { MessagePlugin, PageInfo, PrimaryTableCol, TableRowData } from 'tdesign-vue-next';
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { getList } from '@/api/list'; import { getList } from '@/api/list';
import Trend from '@/components/trend/index.vue'; import Trend from '@/components/trend/index.vue';
import { prefix } from '@/config/global'; import { prefix } from '@/config/global';
import { import { CONTRACT_PAYMENT_TYPES, CONTRACT_STATUS, CONTRACT_TYPES } from '@/constants';
CONTRACT_PAYMENT_TYPES, import { t } from '@/locales';
CONTRACT_STATUS,
CONTRACT_STATUS_OPTIONS,
CONTRACT_TYPE_OPTIONS,
CONTRACT_TYPES,
} from '@/constants';
import { useSettingStore } from '@/store'; import { useSettingStore } from '@/store';
interface FormData { interface FormData {
@ -132,37 +142,51 @@ interface FormData {
} }
const store = useSettingStore(); const store = useSettingStore();
const router = useRouter();
const CONTRACT_STATUS_OPTIONS = [
{ value: CONTRACT_STATUS.FAIL, label: t('components.commonTable.contractStatusEnum.fail') },
{ value: CONTRACT_STATUS.AUDIT_PENDING, label: t('components.commonTable.contractStatusEnum.audit') },
{ value: CONTRACT_STATUS.EXEC_PENDING, label: t('components.commonTable.contractStatusEnum.pending') },
{ value: CONTRACT_STATUS.EXECUTING, label: t('components.commonTable.contractStatusEnum.executing') },
{ value: CONTRACT_STATUS.FINISH, label: t('components.commonTable.contractStatusEnum.finish') },
];
const CONTRACT_TYPE_OPTIONS = [
{ value: CONTRACT_TYPES.MAIN, label: t('components.commonTable.contractTypeEnum.main') },
{ value: CONTRACT_TYPES.SUB, label: t('components.commonTable.contractTypeEnum.sub') },
{ value: CONTRACT_TYPES.SUPPLEMENT, label: t('components.commonTable.contractTypeEnum.supplement') },
];
const COLUMNS: PrimaryTableCol[] = [ const COLUMNS: PrimaryTableCol[] = [
{ {
title: '合同名称', title: t('components.commonTable.contractName'),
fixed: 'left', fixed: 'left',
width: 280, width: 280,
ellipsis: true, ellipsis: true,
align: 'left', align: 'left',
colKey: 'name', colKey: 'name',
}, },
{ title: '合同状态', colKey: 'status', width: 160 }, { title: t('components.commonTable.contractStatus'), colKey: 'status', width: 160 },
{ {
title: '合同编号', title: t('components.commonTable.contractNum'),
width: 160, width: 160,
ellipsis: true, ellipsis: true,
colKey: 'no', colKey: 'no',
}, },
{ {
title: '合同类型', title: t('components.commonTable.contractType'),
width: 160, width: 160,
ellipsis: true, ellipsis: true,
colKey: 'contractType', colKey: 'contractType',
}, },
{ {
title: '合同收付类型', title: t('components.commonTable.contractPayType'),
width: 160, width: 160,
ellipsis: true, ellipsis: true,
colKey: 'paymentType', colKey: 'paymentType',
}, },
{ {
title: '合同金额 (元)', title: t('components.commonTable.contractAmount'),
width: 160, width: 160,
ellipsis: true, ellipsis: true,
colKey: 'amount', colKey: 'amount',
@ -172,7 +196,7 @@ const COLUMNS: PrimaryTableCol[] = [
fixed: 'right', fixed: 'right',
width: 160, width: 160,
colKey: 'op', colKey: 'op',
title: '操作', title: t('components.commonTable.operation'),
}, },
]; ];
@ -250,6 +274,10 @@ const handleClickDelete = (slot: { row: { rowIndex: number } }) => {
const onReset = (val: unknown) => { const onReset = (val: unknown) => {
console.log(val); console.log(val);
}; };
const handleClickDetail = () => {
router.push('/detail/base');
};
const onSubmit = (val: unknown) => { const onSubmit = (val: unknown) => {
console.log(val); console.log(val);
console.log(formData.value); console.log(formData.value);
@ -260,9 +288,6 @@ const rehandlePageChange = (pageInfo: PageInfo, newDataSource: TableRowData[]) =
const rehandleChange = (changeParams: unknown, triggerAndData: unknown) => { const rehandleChange = (changeParams: unknown, triggerAndData: unknown) => {
console.log('统一Change', changeParams, triggerAndData); console.log('统一Change', changeParams, triggerAndData);
}; };
const rehandleClickOp = (ctx: unknown) => {
console.log(ctx);
};
const headerAffixedTop = computed( const headerAffixedTop = computed(
() => () =>

View File

@ -13,7 +13,7 @@
</template> </template>
<template #status> <template #status>
<t-tag :theme="product.isSetup ? 'success' : 'default'" :disabled="!product.isSetup">{{ <t-tag :theme="product.isSetup ? 'success' : 'default'" :disabled="!product.isSetup">{{
product.isSetup ? '已启用' : '已停用' product.isSetup ? $t('components.isSetup.on') : $t('components.isSetup.off')
}}</t-tag> }}</t-tag>
</template> </template>
<template #content> <template #content>
@ -36,12 +36,12 @@
trigger="click" trigger="click"
:options="[ :options="[
{ {
content: '管理', content: $t('components.manage'),
value: 'manage', value: 'manage',
onClick: () => handleClickManage(product), onClick: () => handleClickManage(product),
}, },
{ {
content: '删除', content: $t('components.delete'),
value: 'delete', value: 'delete',
onClick: () => handleClickDelete(product), onClick: () => handleClickDelete(product),
}, },

View File

@ -7,14 +7,6 @@ export const CONTRACT_STATUS = {
FINISH: 4, FINISH: 4,
}; };
export const CONTRACT_STATUS_OPTIONS = [
{ value: CONTRACT_STATUS.FAIL, label: '审核失败' },
{ value: CONTRACT_STATUS.AUDIT_PENDING, label: '待审核' },
{ value: CONTRACT_STATUS.EXEC_PENDING, label: '待履行' },
{ value: CONTRACT_STATUS.EXECUTING, label: '审核成功' },
{ value: CONTRACT_STATUS.FINISH, label: '已完成' },
];
// 合同类型枚举 // 合同类型枚举
export const CONTRACT_TYPES = { export const CONTRACT_TYPES = {
MAIN: 0, MAIN: 0,
@ -22,12 +14,6 @@ export const CONTRACT_TYPES = {
SUPPLEMENT: 2, SUPPLEMENT: 2,
}; };
export const CONTRACT_TYPE_OPTIONS = [
{ value: CONTRACT_TYPES.MAIN, label: '主合同' },
{ value: CONTRACT_TYPES.SUB, label: '子合同' },
{ value: CONTRACT_TYPES.SUPPLEMENT, label: '补充合同' },
];
// 合同收付类型枚举 // 合同收付类型枚举
export const CONTRACT_PAYMENT_TYPES = { export const CONTRACT_PAYMENT_TYPES = {
PAYMENT: 0, PAYMENT: 0,

View File

@ -25,7 +25,7 @@ const settingStore = useSettingStore();
const getWrapStyle = computed((): CSSProperties => { const getWrapStyle = computed((): CSSProperties => {
return { return {
height: `${unref(heightRef)}px`, height: `${heightRef.value}px`,
}; };
}); });

View File

@ -23,24 +23,34 @@
<!-- 全局通知 --> <!-- 全局通知 -->
<notice /> <notice />
<t-tooltip placement="bottom" content="代码仓库"> <t-tooltip placement="bottom" :content="$t('layout.header.code')">
<t-button theme="default" shape="square" variant="text" @click="navToGitHub"> <t-button theme="default" shape="square" variant="text" @click="navToGitHub">
<t-icon name="logo-github" /> <t-icon name="logo-github" />
</t-button> </t-button>
</t-tooltip> </t-tooltip>
<t-tooltip placement="bottom" content="帮助文档"> <t-tooltip placement="bottom" :content="$t('layout.header.help')">
<t-button theme="default" shape="square" variant="text" @click="navToHelper"> <t-button theme="default" shape="square" variant="text" @click="navToHelper">
<t-icon name="help-circle" /> <t-icon name="help-circle" />
</t-button> </t-button>
</t-tooltip> </t-tooltip>
<t-dropdown trigger="click">
<t-button theme="default" shape="square" variant="text">
<translate-icon />
</t-button>
<t-dropdown-menu>
<t-dropdown-item v-for="(lang, index) in langList" :key="index" :value="lang.value" @click="changeLang">{{
lang.content
}}</t-dropdown-item></t-dropdown-menu
>
</t-dropdown>
<t-dropdown :min-column-width="120" trigger="click"> <t-dropdown :min-column-width="120" trigger="click">
<template #dropdown> <template #dropdown>
<t-dropdown-menu> <t-dropdown-menu>
<t-dropdown-item class="operations-dropdown-container-item" @click="handleNav('/user/index')"> <t-dropdown-item class="operations-dropdown-container-item" @click="handleNav('/user/index')">
<t-icon name="user-circle"></t-icon> <user-circle-icon />{{ $t('layout.header.user') }}
</t-dropdown-item> </t-dropdown-item>
<t-dropdown-item class="operations-dropdown-container-item" @click="handleLogout"> <t-dropdown-item class="operations-dropdown-container-item" @click="handleLogout">
<t-icon name="poweroff"></t-icon>退 <poweroff-icon />{{ $t('layout.header.signOut') }}
</t-dropdown-item> </t-dropdown-item>
</t-dropdown-menu> </t-dropdown-menu>
</template> </template>
@ -49,12 +59,12 @@
<t-icon class="header-user-avatar" name="user-circle" /> <t-icon class="header-user-avatar" name="user-circle" />
</template> </template>
<div class="header-user-account">{{ user.userInfo.name }}</div> <div class="header-user-account">{{ user.userInfo.name }}</div>
<template #suffix><t-icon name="chevron-down" /></template> <template #suffix><chevron-down-icon /></template>
</t-button> </t-button>
</t-dropdown> </t-dropdown>
<t-tooltip placement="bottom" content="系统设置"> <t-tooltip placement="bottom" :content="$t('layout.header.setting')">
<t-button theme="default" shape="square" variant="text" @click="toggleSettingPanel"> <t-button theme="default" shape="square" variant="text" @click="toggleSettingPanel">
<t-icon name="setting" /> <setting-icon />
</t-button> </t-button>
</t-tooltip> </t-tooltip>
</div> </div>
@ -64,12 +74,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ChevronDownIcon, PoweroffIcon, SettingIcon, TranslateIcon, UserCircleIcon } from 'tdesign-icons-vue-next';
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { computed } from 'vue'; import { computed } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import LogoFull from '@/assets/assets-logo-full.svg?component'; import LogoFull from '@/assets/assets-logo-full.svg?component';
import { prefix } from '@/config/global'; import { prefix } from '@/config/global';
import { langList } from '@/locales/index';
import { useLocale } from '@/locales/useLocale';
import { getActive } from '@/router'; import { getActive } from '@/router';
import { useSettingStore, useUserStore } from '@/store'; import { useSettingStore, useUserStore } from '@/store';
import type { MenuRoute } from '@/types/interface'; import type { MenuRoute } from '@/types/interface';
@ -135,6 +148,13 @@ const menuCls = computed(() => {
]; ];
}); });
const menuTheme = computed(() => props.theme as 'light' | 'dark'); const menuTheme = computed(() => props.theme as 'light' | 'dark');
//
const { changeLocale } = useLocale();
const changeLang = ({ value: lang }: { value: string }) => {
changeLocale(lang);
};
const changeCollapsed = () => { const changeCollapsed = () => {
settingStore.updateConfig({ settingStore.updateConfig({
isSidebarCompact: !settingStore.isSidebarCompact, isSidebarCompact: !settingStore.isSidebarCompact,
@ -177,6 +197,7 @@ const navToHelper = () => {
z-index: 10; z-index: 10;
width: auto; width: auto;
transition: all 0.3s; transition: all 0.3s;
&-compact { &-compact {
left: 64px; left: 64px;
} }
@ -188,6 +209,7 @@ const navToHelper = () => {
display: inline-flex; display: inline-flex;
} }
} }
.header-menu { .header-menu {
flex: 1 1 1; flex: 1 1 1;
display: inline-flex; display: inline-flex;
@ -229,6 +251,7 @@ const navToHelper = () => {
.t-logo { .t-logo {
width: 100%; width: 100%;
height: 100%; height: 100%;
&:hover { &:hover {
cursor: pointer; cursor: pointer;
} }
@ -254,12 +277,14 @@ const navToHelper = () => {
color: var(--td-text-color-primary); color: var(--td-text-color-primary);
} }
} }
.t-menu--dark { .t-menu--dark {
.t-head-menu__inner { .t-head-menu__inner {
border-bottom: 1px solid var(--td-gray-color-10); border-bottom: 1px solid var(--td-gray-color-10);
} }
.header-user-account { .header-user-account {
color: rgba(255, 255, 255, 0.55); color: rgb(255 255 255 / 55%);
} }
} }
@ -280,8 +305,9 @@ const navToHelper = () => {
:deep(.t-dropdown__item) { :deep(.t-dropdown__item) {
width: 100%; width: 100%;
margin-bottom: 0px; margin-bottom: 0;
} }
&:last-child { &:last-child {
:deep(.t-dropdown__item) { :deep(.t-dropdown__item) {
margin-bottom: 8px; margin-bottom: 8px;

View File

@ -29,29 +29,29 @@
}" }"
> >
<template v-if="!routeItem.isHome"> <template v-if="!routeItem.isHome">
{{ routeItem.title }} {{ renderTitle(routeItem.title) }}
</template> </template>
<t-icon v-else name="home" /> <t-icon v-else name="home" />
<template #dropdown> <template #dropdown>
<t-dropdown-menu> <t-dropdown-menu>
<t-dropdown-item @click="() => handleRefresh(routeItem, index)"> <t-dropdown-item @click="() => handleRefresh(routeItem, index)">
<t-icon name="refresh" /> <t-icon name="refresh" />
刷新 {{ $t('layout.tagTabs.refresh') }}
</t-dropdown-item> </t-dropdown-item>
<t-dropdown-item v-if="index > 1" @click="() => handleCloseAhead(routeItem.path, index)"> <t-dropdown-item v-if="index > 1" @click="() => handleCloseAhead(routeItem.path, index)">
<t-icon name="arrow-left" /> <t-icon name="arrow-left" />
关闭左侧 {{ $t('layout.tagTabs.closeLeft') }}
</t-dropdown-item> </t-dropdown-item>
<t-dropdown-item <t-dropdown-item
v-if="index < tabRouters.length - 1" v-if="index < tabRouters.length - 1"
@click="() => handleCloseBehind(routeItem.path, index)" @click="() => handleCloseBehind(routeItem.path, index)"
> >
<t-icon name="arrow-right" /> <t-icon name="arrow-right" />
关闭右侧 {{ $t('layout.tagTabs.closeRight') }}
</t-dropdown-item> </t-dropdown-item>
<t-dropdown-item v-if="tabRouters.length > 2" @click="() => handleCloseOther(routeItem.path, index)"> <t-dropdown-item v-if="tabRouters.length > 2" @click="() => handleCloseOther(routeItem.path, index)">
<t-icon name="close-circle" /> <t-icon name="close-circle" />
关闭其它 {{ $t('layout.tagTabs.closeOther') }}
</t-dropdown-item> </t-dropdown-item>
</t-dropdown-menu> </t-dropdown-menu>
</template> </template>
@ -75,6 +75,7 @@ import { computed, nextTick, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { prefix } from '@/config/global'; import { prefix } from '@/config/global';
import { useLocale } from '@/locales/useLocale';
import { useSettingStore, useTabsRouterStore } from '@/store'; import { useSettingStore, useTabsRouterStore } from '@/store';
import type { TRouterInfo, TTabRemoveOptions } from '@/types/interface'; import type { TRouterInfo, TTabRemoveOptions } from '@/types/interface';
@ -90,6 +91,8 @@ const tabsRouterStore = useTabsRouterStore();
const tabRouters = computed(() => tabsRouterStore.tabRouters.filter((route) => route.isAlive || route.isHome)); const tabRouters = computed(() => tabsRouterStore.tabRouters.filter((route) => route.isAlive || route.isHome));
const activeTabPath = ref(''); const activeTabPath = ref('');
const { locale } = useLocale();
const handleChangeCurrentTab = (path: string) => { const handleChangeCurrentTab = (path: string) => {
const { tabRouters } = tabsRouterStore; const { tabRouters } = tabsRouterStore;
const route = tabRouters.find((i) => i.path === path); const route = tabRouters.find((i) => i.path === path);
@ -104,6 +107,10 @@ const handleRemove = (options: TTabRemoveOptions) => {
if ((options.value as string) === route.path) router.push({ path: nextRouter.path, query: nextRouter.query }); if ((options.value as string) === route.path) router.push({ path: nextRouter.path, query: nextRouter.query });
}; };
const renderTitle = (title: string | Record<string, string>) => {
if (typeof title === 'string') return title;
return title[locale.value];
};
const handleRefresh = (route: TRouterInfo, routeIdx: number) => { const handleRefresh = (route: TRouterInfo, routeIdx: number) => {
tabsRouterStore.toggleTabRouterAlive(routeIdx); tabsRouterStore.toggleTabRouterAlive(routeIdx);
nextTick(() => { nextTick(() => {

View File

@ -6,16 +6,16 @@
<template #icon> <template #icon>
<component :is="menuIcon(item)" class="t-icon"></component> <component :is="menuIcon(item)" class="t-icon"></component>
</template> </template>
{{ item.title }} {{ renderMenuTitle(item.title) }}
</t-menu-item> </t-menu-item>
<t-menu-item v-else :name="item.path" :value="getPath(item)" :to="item.path"> <t-menu-item v-else :name="item.path" :value="getPath(item)" :to="item.path">
<template #icon> <template #icon>
<component :is="menuIcon(item)" class="t-icon"></component> <component :is="menuIcon(item)" class="t-icon"></component>
</template> </template>
{{ item.title }} {{ renderMenuTitle(item.title) }}
</t-menu-item> </t-menu-item>
</template> </template>
<t-submenu v-else :name="item.path" :value="item.path" :title="item.title"> <t-submenu v-else :name="item.path" :value="item.path" :title="renderMenuTitle(item.title)">
<template #icon> <template #icon>
<component :is="menuIcon(item)" class="t-icon"></component> <component :is="menuIcon(item)" class="t-icon"></component>
</template> </template>
@ -28,6 +28,7 @@
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { computed } from 'vue'; import { computed } from 'vue';
import { useLocale } from '@/locales/useLocale';
import { getActive } from '@/router'; import { getActive } from '@/router';
import type { MenuRoute } from '@/types/interface'; import type { MenuRoute } from '@/types/interface';
@ -39,8 +40,10 @@ const props = defineProps({
default: () => [], default: () => [],
}, },
}); });
const active = computed(() => getActive()); const active = computed(() => getActive());
const { locale } = useLocale();
const list = computed(() => { const list = computed(() => {
const { navData } = props; const { navData } = props;
return getMenuList(navData); return getMenuList(navData);
@ -52,6 +55,11 @@ const menuIcon = (item: ListItemType) => {
return RenderIcon; return RenderIcon;
}; };
const renderMenuTitle = (title: string | Record<string, string>) => {
if (typeof title === 'string') return title;
return title[locale.value];
};
const getMenuList = (list: MenuRoute[], basePath?: string): ListItemType[] => { const getMenuList = (list: MenuRoute[], basePath?: string): ListItemType[] => {
if (!list || list.length === 0) { if (!list || list.length === 0) {
return []; return [];

View File

@ -3,9 +3,14 @@
<template #content> <template #content>
<div class="header-msg"> <div class="header-msg">
<div class="header-msg-top"> <div class="header-msg-top">
<p>通知中心</p> <p>{{ $t('layout.notice.title') }}</p>
<t-button v-if="unreadMsg.length > 0" class="clear-btn" variant="text" theme="primary" @click="setRead('all')" <t-button
>清空</t-button v-if="unreadMsg.length > 0"
class="clear-btn"
variant="text"
theme="primary"
@click="setRead('all')"
>{{ $t('layout.notice.clear') }}</t-button
> >
</div> </div>
<t-list v-if="unreadMsg.length > 0" class="narrow-scrollbar" :split="false"> <t-list v-if="unreadMsg.length > 0" class="narrow-scrollbar" :split="false">
@ -16,19 +21,21 @@
</div> </div>
<p class="msg-time">{{ item.date }}</p> <p class="msg-time">{{ item.date }}</p>
<template #action> <template #action>
<t-button size="small" variant="outline" @click="setRead('radio', item)"> 设为已读 </t-button> <t-button size="small" variant="outline" @click="setRead('radio', item)">
{{ $t('layout.notice.setRead') }}
</t-button>
</template> </template>
</t-list-item> </t-list-item>
</t-list> </t-list>
<div v-else class="empty-list"> <div v-else class="empty-list">
<img src="https://tdesign.gtimg.com/pro-template/personal/nothing.png" alt="空" /> <img src="https://tdesign.gtimg.com/pro-template/personal/nothing.png" alt="空" />
<p>暂无通知</p> <p>{{ $t('layout.notice.empty') }}</p>
</div> </div>
<div v-if="unreadMsg.length > 0" class="header-msg-bottom"> <div v-if="unreadMsg.length > 0" class="header-msg-bottom">
<t-button class="header-msg-bottom-link" variant="text" theme="default" block @click="goDetail" <t-button class="header-msg-bottom-link" variant="text" theme="default" block @click="goDetail">{{
>查看全部</t-button $t('layout.notice.viewAll')
> }}</t-button>
</div> </div>
</div> </div>
</template> </template>

View File

@ -2,7 +2,7 @@
<div v-if="layout === 'side'" class="header-menu-search"> <div v-if="layout === 'side'" class="header-menu-search">
<t-input <t-input
:class="['header-search', { 'hover-active': isSearchFocus }]" :class="['header-search', { 'hover-active': isSearchFocus }]"
placeholder="请输入搜索内容" :placeholder="$t('layout.searchPlaceholder')"
@blur="changeSearchFocus(false)" @blur="changeSearchFocus(false)"
@focus="changeSearchFocus(true)" @focus="changeSearchFocus(true)"
> >
@ -56,6 +56,7 @@ const changeSearchFocus = (value: boolean) => {
.header-menu-search { .header-menu-search {
display: flex; display: flex;
margin-left: 16px; margin-left: 16px;
.hover-active { .hover-active {
background: var(--td-bg-color-secondarycontainer); background: var(--td-bg-color-secondarycontainer);
} }
@ -63,20 +64,22 @@ const changeSearchFocus = (value: boolean) => {
.t-icon { .t-icon {
color: var(--td-text-color-primary) !important; color: var(--td-text-color-primary) !important;
} }
.header-search { .header-search {
:deep(.t-input) { :deep(.t-input) {
border: none; border: none;
outline: none; outline: none;
box-shadow: none; box-shadow: none;
transition: background @anim-duration-base linear; transition: background @anim-duration-base linear;
.t-input__inner { .t-input__inner {
transition: background @anim-duration-base linear; transition: background @anim-duration-base linear;
}
.t-input__inner {
background: none; background: none;
} }
&:hover { &:hover {
background: var(--td-bg-color-secondarycontainer); background: var(--td-bg-color-secondarycontainer);
.t-input__inner { .t-input__inner {
background: var(--td-bg-color-secondarycontainer); background: var(--td-bg-color-secondarycontainer);
} }
@ -91,14 +94,17 @@ const changeSearchFocus = (value: boolean) => {
.t-icon { .t-icon {
font-size: 20px; font-size: 20px;
&.general { &.general {
margin-right: 16px; margin-right: 16px;
} }
} }
} }
.search-icon-hide { .search-icon-hide {
opacity: 0; opacity: 0;
} }
.header-menu-search-left { .header-menu-search-left {
display: flex; display: flex;
align-items: center; align-items: center;
@ -106,12 +112,15 @@ const changeSearchFocus = (value: boolean) => {
.header-search { .header-search {
width: 200px; width: 200px;
transition: width @anim-duration-base @anim-time-fn-easing; transition: width @anim-duration-base @anim-time-fn-easing;
:deep(.t-input) { :deep(.t-input) {
border: 0; border: 0;
&:focus { &:focus {
box-shadow: none; box-shadow: none;
} }
} }
&.width-zero { &.width-zero {
width: 0; width: 0;
opacity: 0; opacity: 0;

View File

@ -3,14 +3,14 @@
v-model:visible="showSettingPanel" v-model:visible="showSettingPanel"
size="408px" size="408px"
:footer="false" :footer="false"
header="页面配置" :header="$t('layout.setting.title')"
:close-btn="true" :close-btn="true"
class="setting-drawer-container" class="setting-drawer-container"
@close-btn-click="handleCloseDrawer" @close-btn-click="handleCloseDrawer"
> >
<div class="setting-container"> <div class="setting-container">
<t-form ref="form" :data="formData" label-align="left"> <t-form ref="form" :data="formData" label-align="left">
<div class="setting-group-title">主题模式</div> <div class="setting-group-title">{{ $t('layout.setting.theme.mode') }}</div>
<t-radio-group v-model="formData.mode"> <t-radio-group v-model="formData.mode">
<div v-for="(item, index) in MODE_OPTIONS" :key="index" class="setting-layout-drawer"> <div v-for="(item, index) in MODE_OPTIONS" :key="index" class="setting-layout-drawer">
<div> <div>
@ -21,7 +21,7 @@
</div> </div>
</div> </div>
</t-radio-group> </t-radio-group>
<div class="setting-group-title">主题色</div> <div class="setting-group-title">{{ $t('layout.setting.theme.color') }}</div>
<t-radio-group v-model="formData.brandTheme"> <t-radio-group v-model="formData.brandTheme">
<div v-for="(item, index) in DEFAULT_COLOR_OPTIONS" :key="index" class="setting-layout-drawer"> <div v-for="(item, index) in DEFAULT_COLOR_OPTIONS" :key="index" class="setting-layout-drawer">
<t-radio-button :key="index" :value="item" class="setting-layout-color-group"> <t-radio-button :key="index" :value="item" class="setting-layout-color-group">
@ -53,7 +53,7 @@
</div> </div>
</t-radio-group> </t-radio-group>
<div class="setting-group-title">导航布局</div> <div class="setting-group-title">{{ $t('layout.setting.navigationLayout') }}</div>
<t-radio-group v-model="formData.layout"> <t-radio-group v-model="formData.layout">
<div v-for="(item, index) in LAYOUT_OPTION" :key="index" class="setting-layout-drawer"> <div v-for="(item, index) in LAYOUT_OPTION" :key="index" class="setting-layout-drawer">
<t-radio-button :key="index" :value="item"> <t-radio-button :key="index" :value="item">
@ -70,23 +70,29 @@
<t-switch v-model="formData.isSidebarFixed" /> <t-switch v-model="formData.isSidebarFixed" />
</t-form-item> </t-form-item>
<div class="setting-group-title">元素开关</div> <div class="setting-group-title">{{ $t('layout.setting.element.title') }}</div>
<t-form-item v-show="formData.layout === 'side'" label="显示 Header" name="showHeader"> <t-form-item
v-show="formData.layout === 'side'"
:label="$t('layout.setting.element.showHeader')"
name="showHeader"
>
<t-switch v-model="formData.showHeader" /> <t-switch v-model="formData.showHeader" />
</t-form-item> </t-form-item>
<t-form-item label="显示 Breadcrumbs" name="showBreadcrumb"> <t-form-item :label="$t('layout.setting.element.showBreadcrumb')" name="showBreadcrumb">
<t-switch v-model="formData.showBreadcrumb" /> <t-switch v-model="formData.showBreadcrumb" />
</t-form-item> </t-form-item>
<t-form-item label="显示 Footer" name="showFooter"> <t-form-item :label="$t('layout.setting.element.showFooter')" name="showFooter">
<t-switch v-model="formData.showFooter" /> <t-switch v-model="formData.showFooter" />
</t-form-item> </t-form-item>
<t-form-item label="使用 多标签Tab页" name="isUseTabsRouter"> <t-form-item :label="$t('layout.setting.element.useTagTabs')" name="isUseTabsRouter">
<t-switch v-model="formData.isUseTabsRouter"></t-switch> <t-switch v-model="formData.isUseTabsRouter"></t-switch>
</t-form-item> </t-form-item>
</t-form> </t-form>
<div class="setting-info"> <div class="setting-info">
<p>请复制后手动修改配置文件: /src/config/style.ts</p> <p>{{ $t('layout.setting.tips') }}</p>
<t-button theme="primary" variant="text" @click="handleCopy"> 复制配置项 </t-button> <t-button theme="primary" variant="text" @click="handleCopy">
{{ $t('layout.setting.copy.title') }}
</t-button>
</div> </div>
</div> </div>
</t-drawer> </t-drawer>
@ -104,6 +110,7 @@ import ColorContainer from '@/components/color/index.vue';
import Thumbnail from '@/components/thumbnail/index.vue'; import Thumbnail from '@/components/thumbnail/index.vue';
import { DEFAULT_COLOR_OPTIONS } from '@/config/color'; import { DEFAULT_COLOR_OPTIONS } from '@/config/color';
import STYLE_CONFIG from '@/config/style'; import STYLE_CONFIG from '@/config/style';
import { t } from '@/locales';
import { useSettingStore } from '@/store'; import { useSettingStore } from '@/store';
const settingStore = useSettingStore(); const settingStore = useSettingStore();
@ -111,9 +118,9 @@ const settingStore = useSettingStore();
const LAYOUT_OPTION = ['side', 'top', 'mix']; const LAYOUT_OPTION = ['side', 'top', 'mix'];
const MODE_OPTIONS = [ const MODE_OPTIONS = [
{ type: 'light', text: '明亮' }, { type: 'light', text: t('layout.setting.theme.options.light') },
{ type: 'dark', text: '暗黑' }, { type: 'dark', text: t('layout.setting.theme.options.dark') },
{ type: 'auto', text: '跟随系统' }, { type: 'auto', text: t('layout.setting.theme.options.auto') },
]; ];
const initStyleConfig = () => { const initStyleConfig = () => {

68
src/locales/index.ts Normal file
View File

@ -0,0 +1,68 @@
import { DropdownOption } from 'tdesign-vue-next';
import { computed } from 'vue';
import { createI18n } from 'vue-i18n';
// 导入语言文件
const langModules = import.meta.glob('./lang/*/index.ts', { eager: true });
const langModuleMap = new Map<string, Object>();
export const langCode: Array<string> = [];
export const localeConfigKey = 'tdesign-starter-locale';
// 获取浏览器默认语言环境
const browserLanguage = navigator.language.replace('-', '_');
// 生成语言模块列表
const generateLangModuleMap = () => {
const fullPaths = Object.keys(langModules);
console.log(langModules, 'langModules');
fullPaths.forEach((fullPath) => {
const k = fullPath.replace('./lang', '');
const startIndex = 1;
const lastIndex = k.lastIndexOf('/');
const code = k.substring(startIndex, lastIndex);
langCode.push(code);
console.log(langCode, 'langCode');
langModuleMap.set(code, langModules[fullPath]);
});
};
// 导出 Message
const importMessages = computed(() => {
generateLangModuleMap();
const message: Recordable = {};
langModuleMap.forEach((value: any, key) => {
message[key] = value.default;
});
return message;
});
export const i18n = createI18n({
legacy: false,
locale: localStorage.getItem(localeConfigKey) || browserLanguage || 'zh_CN',
fallbackLocale: 'zh_CN',
messages: importMessages.value,
globalInjection: true,
});
export const langList = computed(() => {
if (langModuleMap.size === 0) generateLangModuleMap();
const list: DropdownOption[] = [];
langModuleMap.forEach((value: any, key) => {
list.push({
content: value.default.lang,
value: key,
});
});
return list;
});
// @ts-ignore
export const { t } = i18n.global;
export default i18n;

View File

@ -0,0 +1,37 @@
export default {
isSetup: {
on: 'Enabled',
off: 'Disabled',
},
manage: 'Manage',
delete: 'Delete',
commonTable: {
contractName: 'Name',
contractStatus: 'Status',
contractNum: 'Number',
contractType: 'Type',
contractPayType: 'Pay Type',
contractAmount: 'Amount',
contractNamePlaceholder: 'enter contract name',
contractStatusPlaceholder: 'enter contract status',
contractNumPlaceholder: 'enter contract number',
contractTypePlaceholder: 'enter contract type',
operation: 'Operation',
detail: 'detail',
delete: 'delete',
contractStatusEnum: {
fail: 'fail',
audit: 'audit',
executing: 'executing',
pending: 'pending',
finish: 'finish',
},
contractTypeEnum: {
main: 'main',
sub: 'sub',
supplement: 'supplement',
},
reset: 'reset',
query: 'query',
},
};

View File

@ -0,0 +1,54 @@
import merge from 'lodash/merge';
import componentsLocale from 'tdesign-vue-next/es/locale/en_US';
import components from './components';
import layout from './layout';
import pages from './pages';
export default {
lang: 'English',
layout,
pages,
components,
constants: {
contract: {
name: 'Name',
status: 'Status',
num: 'Number',
type: 'Type',
typePlaceholder: 'Please enter type',
payType: 'Pay Type',
amount: 'Amount',
amountPlaceholder: 'Please enter amount',
signDate: 'Sign Date',
effectiveDate: 'Effective Date',
endDate: 'End Date',
createDate: 'Create Date',
attachment: 'Attachment',
company: 'Company',
employee: 'Employee',
pay: 'pay',
receive: 'received',
remark: 'remark',
statusOptions: {
fail: 'Failure',
auditPending: 'Pending audit',
execPending: 'Pending performance',
executing: 'Successful',
finish: 'Finish',
},
typeOptions: {
main: 'Master contract',
sub: 'Subcontract',
supplement: 'Supplementary contract',
},
},
},
componentsLocale: merge({}, componentsLocale, {
// 可以在此处定义更多自定义配置,具体可配置内容参看 API 文档
// https://tdesign.tencent.com/vue-next/config?tab=api
// pagination: {
// jumpTo: 'xxx'
// },
}),
};

View File

@ -0,0 +1,52 @@
export default {
header: {
code: 'Code Repository',
help: 'Document',
user: 'Profile',
signOut: 'Sign Out',
setting: 'Setting',
},
notice: {
title: 'Notification Center',
clear: 'Clear',
setRead: 'Set Read',
empty: 'Empty',
emptyNotice: 'No Notice',
viewAll: 'View All',
},
tagTabs: {
closeOther: 'close other',
closeLeft: 'close left',
closeRight: 'close right',
refresh: 'refresh',
},
searchPlaceholder: 'Enter search content',
setting: {
title: 'Setting',
theme: {
mode: 'Theme Mode',
color: 'Theme Color',
options: {
light: 'Light',
dark: 'Dark ',
auto: 'Follow System',
},
},
navigationLayout: 'Navigation Layout',
splitMenu: 'Split MenuOnly Mix mode',
fixedSidebar: 'Fixed Sidebar',
element: {
title: 'Element Switch',
showHeader: 'Show Header',
showBreadcrumb: 'Show Breadcrumb',
showFooter: 'Show Footer',
useTagTabs: 'Use Tag Tabs',
},
tips: 'Please copy and manually modify the configuration file: /src/config/style.ts',
copy: {
title: 'Copy',
success: 'copied',
fail: 'fail to copy',
},
},
};

View File

@ -0,0 +1,62 @@
export default {
outputOverview: {
title: 'In/Out Overview',
subtitle: '(pieces)',
export: 'Export data',
month: {
input: 'Total in store this month',
output: 'Total out store this month',
},
since: 'Since last week',
},
rankList: {
title: 'Sales order ranking',
week: 'This week',
month: 'Latest 3 months',
info: 'Detail',
},
topPanel: {
card1: 'Total Revenue',
card2: 'Total Refund',
card3: 'Active User(s)',
card4: 'Generate Order(s)',
cardTips: 'since last week',
analysis: {
title: 'Analysis Data',
unit: 'ten thousand yuan',
series1: 'this month',
series2: 'last month',
channels: 'Sales Channels',
channel1: 'online',
channel2: 'shop',
channelTips: ' sales ratio',
},
},
saleColumns: {
index: 'Ranking',
productName: 'Customer',
growUp: 'Grow up',
count: 'Count',
operation: 'Operation',
},
buyColumns: {
index: 'Ranking',
productName: 'Supplier',
growUp: 'Grow up',
count: 'Count',
operation: 'Operation',
},
chart: {
week1: 'MON',
week2: 'TUE',
week3: 'WED',
week4: 'THU',
week5: 'FRI',
week6: 'SAT',
week7: 'SUN',
max: 'Max',
min: 'Min',
thisMonth: 'this month',
lastMonth: 'last month',
},
};

View File

@ -0,0 +1,45 @@
export default {
topPanel: {
title: 'Purchase applications for this month',
quarter: 'Quarter on quarter',
paneList: {
totalRequest: 'Apply count',
suppliers: 'Number of Suppliers',
productCategory: 'Product Category',
applicant: 'Number of Application',
completionRate: 'Completion Rate(%)',
arrivalRate: 'Arrival Rate(%)',
},
},
procurement: {
title: 'Trends in purchase requisitions for goods',
goods: {
cup: 'cup',
tea: 'tea',
honey: 'honey',
flour: 'flour',
coffeeMachine: 'coffee machine',
massageMachine: 'massage machine',
},
},
ssl: 'SSL certificate',
sslDescription:
'SSL certificate, also known as a server certificate, is a digital certificate that authenticates the identity of a website and encrypts information sent to the server using SSL technology. Tencent Cloud provides you with a one-stop service for SSL certificates, including application, management, and deployment of both free and paid certificates.',
satisfaction: {
title: 'distribution of satisfaction levels for purchased goods',
export: 'export data',
},
chart: {
week1: 'MON',
week2: 'TUE',
week3: 'WED',
week4: 'THU',
week5: 'FRI',
week6: 'SAT',
week7: 'SUN',
max: 'Max',
min: 'Min',
thisMonth: 'this month',
lastMonth: 'last month',
},
};

View File

@ -0,0 +1,20 @@
export default {
baseInfo: {
title: 'Base Info',
},
changelog: {
title: 'Changelog',
step1: {
title: 'upload file',
subtitle: 'subtitle',
},
step2: {
title: 'modify contract amount',
subtitle: 'subtitle',
},
step3: {
title: 'create contract',
desc: 'administrator',
},
},
};

View File

@ -0,0 +1,43 @@
export default {
baseInfo: {
title: 'Base Info',
},
invoice: {
title: 'Invoice Progress',
step1: {
title: 'Apply',
content: 'The electronic invoice has been submitted on December 21st',
},
step2: {
title: 'Electronic invoice',
content: 'expected to be processed within 1-3 business days.',
},
step3: {
title: 'Invoice is send',
content: 'we will contact you within 7 business days.',
},
step4: {
title: 'Finish',
},
},
product: {
title: 'Product Category',
add: 'add production',
month: 'month',
quarter: 'quarter',
},
detail: {
title: 'Product Procurement Detail',
form: {
applyNo: 'Apply no',
product: 'Name',
productNo: 'No.',
department: 'Department',
num: 'Num',
createTime: 'Create time',
operation: 'Operation',
manage: 'manage',
delete: 'delete',
},
},
};

View File

@ -0,0 +1,32 @@
export default {
deployTrend: {
title: 'Deploy Trend',
warning: 'Warning',
thisMonth: 'this month',
thisWeek: 'this week',
lastMonth: 'last month',
thisYear: 'this year',
lastYear: 'last year',
week1: 'MON',
week2: 'TUE',
week3: 'WED',
week4: 'THU',
week5: 'FRI',
week6: 'SAT',
week7: 'SUN',
},
projectList: {
title: 'Project List',
dialog: {
title: 'Base Info',
},
table: {
name: 'Name',
admin: 'Admin',
createTime: 'Create time',
operation: 'Operation',
manage: 'manage',
delete: 'delete',
},
},
};

View File

@ -0,0 +1,9 @@
export default {
read: 'Read',
unread: 'Unread',
all: 'All',
setRead: 'set as read',
setUnread: 'set as unread',
delete: 'delete',
empty: 'Empty',
};

View File

@ -0,0 +1,27 @@
export default {
title: 'Contract Info',
contractName: 'Name',
contractStatus: 'Status',
contractNum: 'Number',
contractType: 'Type',
contractTypePlaceholder: 'Please enter type',
contractPayType: 'Pay Type',
contractAmount: 'Amount',
contractAmountPlaceholder: 'Please enter amount',
contractSignDate: 'Sign Date',
contractEffectiveDate: 'Effective Date',
contractEndDate: 'End Date',
company: 'Company',
employee: 'Employee',
pay: 'pay',
receive: 'received',
upload: 'upload file',
uploadFile: 'upload contract file',
uploadTips: 'Please upload a PDF file, with a size limit of 60MB.',
otherInfo: 'Other Info',
remark: 'Remark',
remarkPlaceholder: 'please enter remark',
notaryPublic: 'Notary Public',
confirm: 'confirm',
cancel: 'cancel',
};

View File

@ -0,0 +1,53 @@
export default {
step1: {
title: 'Submit Application',
subtitle: 'Submitted on December 21st',
rules: 'rules',
rule1:
'1. After applying for an invoice, the electronic invoice will be issued within 1-3 working days. If the qualification review is passed, the VAT special invoice (paper) will be mailed to you within 10 working days after the electronic invoice is issued;',
rule2: '2. The invoiced amount will be the actual amount you paid;',
rule3: '3. For any questions, please contact us directly at 13300001111.',
contractName: 'Name',
contractTips: 'Please select a contract name',
invoiceType: 'Invoice type',
amount: 'Amount',
submit: 'Submit Application',
},
step2: {
title: 'Electronic Information',
subtitle: 'Contact Customer Service if you have any questions',
invoiceTitle: 'Invoice Title',
taxNum: 'Tax Num',
address: 'Address',
bank: 'Bank',
bankAccount: 'Bank Account',
email: 'Email',
tel: 'Tel',
invoiceTitlePlaceholder: 'please enter invoice title',
taxNumPlaceholder: 'please enter tax num',
addressPlaceholder: 'please enter address',
bankPlaceholder: 'please enter bank',
bankAccountPlaceholder: 'please enter bank account',
emailPlaceholder: 'please enter email',
telPlaceholder: 'please enter tel',
},
step3: {
title: 'Invoice Mailed',
subtitle: 'Contact us after the electronic invoice is issued',
consignee: 'Consignee',
mobileNum: 'Mobile Num',
deliveryAddress: 'Address',
fullAddress: 'Full Address',
},
step4: {
title: 'Application Completed',
subtitle: 'Contact Customer Service if you have any questions',
finishTitle: 'Application is completed.',
finishTips:
'The electronic invoice is expected to be sent to your email within 1-3 working days. Please be patient for the delivery of the paper invoice.',
reapply: 'reapply',
check: 'check progress',
},
preStep: 'pre step',
nextStep: 'next step',
};

View File

@ -0,0 +1,33 @@
import dashboardBase from './dashboard-base';
import dashboardDetail from './dashboard-detail';
import detailBase from './detail-base';
import detailCard from './detail-card';
import detailDeploy from './detail-deploy';
import detailSecondary from './detail-secondary';
import formBase from './form-base';
import formStep from './form-step';
import listBase from './list-base';
import listCard from './list-card';
import listFilter from './list-filter';
import listTree from './list-tree';
import login from './login';
import result from './result';
import user from './user';
export default {
dashboardBase,
dashboardDetail,
listBase,
listCard,
listFilter,
listTree,
detailBase,
detailCard,
detailDeploy,
detailSecondary,
formBase,
formStep,
user,
login,
result,
};

View File

@ -0,0 +1,25 @@
export default {
export: 'export',
create: 'create',
select: 'select',
items: 'items',
contractName: 'Name',
contractStatus: 'Status',
contractNum: 'Number',
contractType: 'Type',
contractPayType: 'Pay Type',
contractAmount: 'Amount',
operation: 'Operation',
detail: 'detail',
delete: 'delete',
pay: 'pay',
receive: 'received',
placeholder: 'please enter to search',
contractStatusEnum: {
fail: 'fail',
audit: 'audit',
executing: 'executing',
pending: 'pending',
finish: 'finish',
},
};

View File

@ -0,0 +1,13 @@
export default {
create: 'Create Product',
placeholder: 'please enter to search',
productName: 'Name',
productStatus: 'Status',
productDescription: 'Description',
productType: 'Type',
productRemark: 'Remark',
productStatusEnum: {
off: 'off',
on: 'on',
},
};

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1,3 @@
export default {
placeholder: 'please enter to search',
};

View File

@ -0,0 +1,26 @@
export default {
loginTitle: 'Login in',
noAccount: 'No Account?',
createAccount: 'Create Account',
remember: 'Remember Account',
forget: 'Forget Account',
signIn: 'Sign in',
existAccount: 'Exist Account?',
refresh: 'refresh',
wechatLogin: 'Login with WeChat',
accountLogin: 'Login with Account',
phoneLogin: 'Login with Mobile Phone',
input: {
account: 'please enter account',
password: 'please enter password',
phone: 'please enter phone',
verification: 'please enter verification code',
},
required: {
account: 'account is required',
phone: 'phone is required',
password: 'password is required',
verification: 'verification code is require',
},
sendVerification: 'send',
};

View File

@ -0,0 +1,43 @@
export default {
403: {
tips: 'sorry, you don not have permission to access this page. Please contact the creator through WeCom',
back: 'Back to homepage',
},
404: {
subtitle: 'Sorry, the page is not found',
back: 'Back to homepage',
},
500: {
subtitle: 'Sorry, the server is error',
back: 'Back to homepage',
},
fail: {
title: 'Create fail',
subtitle: 'Sorry, your project creation has failed',
back: 'Back to homepage',
modify: 'Back to modify',
},
success: {
title: 'Project is created',
subtitle: 'Contact the person in charge of distributing the application',
back: 'Back to homepage',
progress: 'Check Progress',
},
maintenance: {
title: 'System maintenance',
subtitle: 'Please try again later',
back: 'Back to homepage',
},
browserIncompatible: {
title: 'browser is incompatible',
subtitle: 'the browser version you are using is too outdated to open the current webpage.',
back: 'Back to homepage',
recommend: 'TDesign Starter recommend the following browser',
},
networkError: {
title: 'Network Error',
subtitle: 'Network error, please try again later',
back: 'Back to homepage',
reload: 'Reload',
},
};

View File

@ -0,0 +1,23 @@
export default {
markDay: 'Good afternoon, today marks your 100th day at Tencent',
personalInfo: {
title: 'Personal Info',
position: 'Employee of the Hong Kong and Macau Business Expansion team',
desc: {
phone: 'Phone',
mobile: 'Mobile',
seat: 'Seat',
email: 'Email',
position: 'Position',
leader: 'Leader',
entity: 'Entity',
joinDay: 'Day of join',
group: 'Group',
},
},
contentList: 'Content List',
visitData: 'Visit Data',
teamMember: 'Team Member',
serviceProduction: 'Service Product',
};

View File

@ -0,0 +1,38 @@
export default {
isSetup: {
on: '已启用',
off: '已停用',
},
manage: '管理',
delete: '删除',
commonTable: {
contractName: '合同名称',
contractNamePlaceholder: '请输入合同名称',
contractStatus: '合同状态',
contractStatusPlaceholder: '请输入合同状态',
contractNum: '合同编号',
contractNumPlaceholder: '请输入合同编号',
contractType: '合同类型',
contractTypePlaceholder: '请选择合同类型',
contractPayType: '合同支付类型',
contractAmount: '合同金额',
operation: '操作',
detail: '详情',
delete: '删除',
placeholder: '请输入内容搜索',
contractStatusEnum: {
fail: '审核失败',
audit: '待审核',
executing: '履行中',
pending: '待履行',
finish: '已完成',
},
contractTypeEnum: {
main: '主合同',
sub: '子合同',
supplement: '补充合同',
},
reset: '重置',
query: '查询',
},
};

View File

@ -0,0 +1,47 @@
import componentsLocale from 'tdesign-vue-next/es/locale/zh_CN';
import components from './components';
import layout from './layout';
import pages from './pages';
export default {
lang: '简体中文',
layout,
pages,
components,
constants: {
contract: {
name: '合同名称',
status: '合同状态',
num: '合同编号',
type: '合同类型',
typePlaceholder: '请输入类型',
payType: '合同收支类型',
amount: '合同金额',
amountPlaceholder: '请输入金额',
signDate: '合同签订日期',
effectiveDate: '合同生效日期',
endDate: '合同结束日期',
createDate: '合同创建时间',
company: '甲方',
employee: '乙方',
pay: '付款',
receive: '收款',
remark: '备注',
attachment: '附件',
statusOptions: {
fail: '审核失败',
auditPending: '待审核',
execPending: '待履行',
executing: '审核成功',
finish: '已完成',
},
typeOptions: {
main: '主合同',
sub: '子合同',
supplement: '补充合同',
},
},
},
componentsLocale,
};

View File

@ -0,0 +1,52 @@
export default {
header: {
code: '代码仓库',
help: '帮助文档',
user: '个人中心',
signOut: '退出登录',
setting: '系统设置',
},
notice: {
title: '通知中心',
clear: '清空',
setRead: '设为已读',
empty: '空',
emptyNotice: '暂无通知',
viewAll: '查看全部',
},
searchPlaceholder: '请输入搜索内容',
tagTabs: {
closeOther: '关闭其他',
closeLeft: '关闭左侧',
closeRight: '关闭右侧',
refresh: '刷新',
},
setting: {
title: '页面配置',
theme: {
mode: '主题模式',
color: '主题色',
options: {
light: '明亮',
dark: '暗黑',
auto: '跟随系统',
},
},
navigationLayout: '导航布局',
splitMenu: '分割菜单(混合模式下有效)',
fixedSidebar: '固定侧边栏',
element: {
title: '元素开关',
showHeader: '显示顶栏',
showBreadcrumb: '显示面包屑',
showFooter: '显示页脚',
useTagTabs: '展示多标签Tab页',
},
tips: '请复制后手动修改配置文件: /src/config/style.ts',
copy: {
title: '复制配置项',
success: '复制成功',
fail: '复制失败',
},
},
};

View File

@ -0,0 +1,63 @@
export default {
title: '概览仪表盘',
outputOverview: {
title: '出入库概览',
subtitle: '(件)',
export: '导出数据',
month: {
input: '本月入库总计(件)',
output: '本月出库总计(件)',
},
since: '自从上周以来',
},
rankList: {
title: '销售订单排名',
week: '本周',
month: '近三月',
info: '详情',
},
topPanel: {
card1: '总收入',
card2: '总退款',
card3: '活跃用户(个)',
card4: '产生订单(个)',
cardTips: '自从上周以来',
analysis: {
title: '统计数据',
unit: '万元',
series1: '本月',
series2: '上月',
channels: '销售渠道',
channel1: '线上',
channel2: '门店',
channelTips: '销售占比',
},
},
saleColumns: {
index: '排名',
productName: '客户名称',
growUp: '较上周',
count: '订单量',
operation: '操作',
},
buyColumns: {
index: '排名',
productName: '供应商名称',
growUp: '较上周',
count: '订单量',
operation: '操作',
},
chart: {
week1: '周一',
week2: '周二',
week3: '周三',
week4: '周四',
week5: '周五',
week6: '周六',
week7: '周日',
max: '最大值',
min: '最小值',
thisMonth: '本月',
lastMonth: '上月',
},
};

View File

@ -0,0 +1,44 @@
export default {
topPanel: {
title: '本月采购申请情况',
quarter: '环比',
paneList: {
totalRequest: '总申请数(次)',
suppliers: '供应商数量(个)',
productCategory: '采购商品品类(类)',
applicant: '申请人数量(人)',
completionRate: '申请完成率(%',
arrivalRate: '到货及时率(%',
},
},
procurement: {
title: '采购商品申请趋势',
goods: {
cup: '杯子',
tea: '茶叶',
honey: '蜂蜜',
flour: '面粉',
coffeeMachine: '咖啡机',
massageMachine: '按摩仪',
},
},
ssl: 'SSL证书',
sslDescription: 'SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部署',
satisfaction: {
title: '采购商品满意度分布',
export: '导出数据',
},
chart: {
week1: '周一',
week2: '周二',
week3: '周三',
week4: '周四',
week5: '周五',
week6: '周六',
week7: '周日',
max: '最大值',
min: '最小值',
thisMonth: '本月',
lastMonth: '上月',
},
};

View File

@ -0,0 +1,20 @@
export default {
baseInfo: {
title: '基本信息',
},
changelog: {
title: '变更记录',
step1: {
title: '上传合同附件',
subtitle: '这里是提示文字',
},
step2: {
title: '修改合同金额',
subtitle: '这里是提示文字',
},
step3: {
title: '新建合同',
desc: '管理员-李川操作',
},
},
};

View File

@ -0,0 +1,43 @@
export default {
baseInfo: {
title: '基本信息',
},
invoice: {
title: '发票进度',
step1: {
title: '申请提交',
content: '已于12月21日提交',
},
step2: {
title: '电子发票',
content: '预计13个工作日',
},
step3: {
title: '发票已邮寄',
content: '电子发票开出后7个工作日联系',
},
step4: {
title: '完成',
},
},
product: {
title: '产品目录',
add: '新增产品',
month: '月份',
quarter: '季度',
},
detail: {
title: '产品采购明细',
form: {
applyNo: '申请号',
product: '产品名称',
productNo: '产品编号',
operation: '操作',
department: '申请部门',
num: '采购数量',
createTime: '创建时间',
manage: '管理',
delete: '删除',
},
},
};

View File

@ -0,0 +1,32 @@
export default {
deployTrend: {
title: '部署趋势',
warning: '告警情况',
thisMonth: '本月',
thisWeek: '本周',
lastMonth: '上月',
thisYear: '今年',
lastYear: '去年',
week1: '周一',
week2: '周二',
week3: '周三',
week4: '周四',
week5: '周五',
week6: '周六',
week7: '周日',
},
projectList: {
title: '项目列表',
dialog: {
title: '基本信息',
},
table: {
name: '名称',
admin: '管理员',
createTime: '创建时间',
operation: '操作',
manage: '管理',
delete: '删除',
},
},
};

View File

@ -0,0 +1,9 @@
export default {
read: '已读通知',
unread: '未读通知',
all: '全部通知',
setRead: '设为已读',
setUnread: '设为未读',
delete: '删除通知',
empty: '暂无通知',
};

View File

@ -0,0 +1,27 @@
export default {
title: '合同信息',
contractName: '合同名称',
contractStatus: '合同状态',
contractNum: '合同编号',
contractType: '合同类型',
contractTypePlaceholder: '请输入类型',
contractPayType: '合同收支类型',
contractAmount: '合同金额',
contractAmountPlaceholder: '请输入金额',
contractSignDate: '合同签订日期',
contractEffectiveDate: '合同生效日期',
contractEndDate: '合同结束日期',
company: '甲方',
employee: '乙方',
pay: '付款',
receive: '收款',
upload: '上传文件',
uploadFile: '上传合同',
uploadTips: '请上传pdf文件大小在60M以内',
otherInfo: '其他信息',
remark: '备注',
remarkPlaceholder: '请输入备注',
notaryPublic: '公证人',
confirm: '确认提交',
cancel: '取消',
};

View File

@ -0,0 +1,54 @@
export default {
step1: {
title: '提交申请',
subtitle: '已于12月21日提交',
rules: '发票开具规则',
rule1:
'1、申请开票后电子发票在13个工作日内开具增值税专用发票纸质如资质审核通过将在电子发票开具后10个工作日内为您寄出',
rule2: '2、开票金额为您实际支付金额',
rule3: '3、如有疑问请直接联系13300001111。',
contractName: '合同名称',
contractTips: '请选择合同名称',
invoiceType: '发票类型',
amount: '开票金额',
submit: '提交申请',
},
step2: {
title: '电子信息',
subtitle: '如有疑问联系客服',
invoiceTitle: '发票抬头',
taxNum: '纳税人识别号',
address: '地址',
bank: '开户行',
bankAccount: '银行账号',
email: '邮箱',
tel: '手机号',
titlePlaceholder: '请输入电子信息',
subtitlePlaceholder: '请输入如有疑问联系客服',
invoiceTitlePlaceholder: '请输入发票抬头',
taxNumPlaceholder: '请输入纳税人识别号',
addressPlaceholder: '请输入地址',
bankPlaceholder: '请输入开户行',
bankAccountPlaceholder: '请输入银行账号',
emailPlaceholder: '请输入邮箱',
telPlaceholder: '请输入手机号',
},
step3: {
title: '发票已邮寄',
subtitle: '电子发票开出后联系',
consignee: '收货人',
mobileNum: '手机号码',
deliveryAddress: '收货地址',
fullAddress: '详细地址',
},
step4: {
title: '完成申请',
subtitle: '如有疑问联系客服',
finishTitle: '完成开票申请',
finishTips: '预计13个工作日会将电子发票发至邮箱发票邮寄请耐心等待',
reapply: '再次申请',
check: '查看进度',
},
preStep: '上一步',
nextStep: '下一步',
};

View File

@ -0,0 +1,33 @@
import dashboardBase from './dashboard-base';
import dashboardDetail from './dashboard-detail';
import detailBase from './detail-base';
import detailCard from './detail-card';
import detailDeploy from './detail-deploy';
import detailSecondary from './detail-secondary';
import formBase from './form-base';
import formStep from './form-step';
import listBase from './list-base';
import listCard from './list-card';
import listFilter from './list-filter';
import listTree from './list-tree';
import login from './login';
import result from './result';
import user from './user';
export default {
dashboardBase,
dashboardDetail,
listBase,
listCard,
listFilter,
listTree,
detailBase,
detailCard,
detailDeploy,
detailSecondary,
formBase,
formStep,
user,
login,
result,
};

View File

@ -0,0 +1,25 @@
export default {
export: '导出合同',
create: '新建合同',
select: '已选',
items: '项',
contractName: '合同名称',
contractStatus: '合同状态',
contractNum: '合同编号',
contractType: '合同类型',
contractPayType: '合同收支类型',
contractAmount: '合同金额',
operation: '操作',
detail: '详情',
delete: '删除',
pay: '付款',
receive: '收款',
placeholder: '请输入内容搜索',
contractStatusEnum: {
fail: '审核失败',
audit: '待审核',
executing: '履行中',
pending: '待履行',
finish: '已完成',
},
};

View File

@ -0,0 +1,13 @@
export default {
create: '新建产品',
placeholder: '请输入内容搜索',
productName: '产品名称',
productStatus: '产品状态',
productDescription: '产品描述',
productType: '产品类型',
productRemark: '备注',
productStatusEnum: {
off: '停用',
on: '启用',
},
};

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1,3 @@
export default {
placeholder: '请输入内容进行搜索',
};

View File

@ -0,0 +1,27 @@
export default {
loginTitle: '登录到',
noAccount: '没有账号吗?',
existAccount: '已有账号?',
createAccount: '注册新账号',
remember: '记住账号',
forget: '忘记账号',
signIn: '登录',
register: '注册',
refresh: '刷新',
wechatLogin: '使用微信扫一扫登录',
accountLogin: '使用账号登录',
phoneLogin: '使用手机号登录',
input: {
account: '请输入账号',
password: '请输入登录密码',
phone: '请输入手机号',
verification: '请输入验证码',
},
required: {
account: '账号必填',
phone: '手机号必填',
password: '密码必填',
verification: '验证码必填',
},
sendVerification: '发送验证码',
};

View File

@ -0,0 +1,43 @@
export default {
403: {
tips: '抱歉,您无权限访问此页面,企业微信联系创建者',
back: '返回首页',
},
404: {
subtitle: '抱歉,您访问的页面不存在',
back: '返回首页',
},
500: {
subtitle: '抱歉,服务器出错啦',
back: '返回首页',
},
fail: {
title: '创建失败',
subtitle: '抱歉,您的项目创建失败,企业微信联系检查创建者权限,或返回修改。',
back: '回到首页',
progress: '返回修改',
},
success: {
title: '项目已创建成功',
subtitle: '可以联系负责人分发应用',
back: '回到首页',
progress: '查看进度',
},
maintenance: {
title: '系统维护中',
subtitle: '系统维护中,请稍后再试',
back: '回到首页',
},
browserIncompatible: {
title: '浏览器不兼容',
subtitle: '抱歉,您正在使用的浏览器版本过低,无法打开当前网页。',
back: '回到首页',
recommend: 'TDesign Starter 推荐以下主流浏览器',
},
networkError: {
title: '网络异常',
subtitle: '网络异常, 请稍后重试',
back: '回到首页',
reload: '重新加载',
},
};

View File

@ -0,0 +1,22 @@
export default {
markDay: '下午好,今天是你加入鹅厂的第 100 天',
personalInfo: {
title: '个人信息',
position: '港澳业务拓展组员工 直客销售 ',
desc: {
phone: '座机',
mobile: '手机',
seat: '座位',
email: '邮箱',
position: '职位',
leader: '上级',
entity: '主体',
joinDay: '入职时间',
group: '所属团队',
},
},
visitData: '首页访问数据',
contentList: '内容列表',
teamMember: '团队成员',
serviceProduction: '服务产品',
};

27
src/locales/useLocale.ts Normal file
View File

@ -0,0 +1,27 @@
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { i18n, langCode, localeConfigKey } from '@/locales/index';
export function useLocale() {
const { locale } = useI18n({ useScope: 'global' });
function changeLocale(lang: string) {
// 如果切换的语言不在对应语言文件里则默认为简体中文
if (!langCode.includes(lang)) {
lang = 'zh_CN';
}
locale.value = lang;
localStorage.setItem(localeConfigKey, lang);
}
const getComponentsLocale = computed(() => {
return i18n.global.getLocaleMessage(locale.value).componentsLocale;
});
return {
changeLocale,
getComponentsLocale,
locale,
};
}

View File

@ -5,6 +5,7 @@ import { createApp } from 'vue';
import App from './App.vue'; import App from './App.vue';
import router from './router'; import router from './router';
import { store } from './store'; import { store } from './store';
import i18n from './locales';
import 'tdesign-vue-next/es/style/index.css'; import 'tdesign-vue-next/es/style/index.css';
import '@/style/index.less'; import '@/style/index.less';
@ -15,5 +16,6 @@ const app = createApp(App);
app.use(TDesign); app.use(TDesign);
app.use(store); app.use(store);
app.use(router); app.use(router);
app.use(i18n);
app.mount('#app'); app.mount('#app');

View File

@ -1,7 +1,12 @@
<template> <template>
<t-row :gutter="16" class="row-container"> <t-row :gutter="16" class="row-container">
<t-col :xs="12" :xl="9"> <t-col :xs="12" :xl="9">
<t-card title="统计数据" :subtitle="`(万元)${currentMonth}`" class="dashboard-chart-card" :bordered="false"> <t-card
:title="$t('pages.dashboardBase.topPanel.analysis.title')"
:subtitle="currentMonth"
class="dashboard-chart-card"
:bordered="false"
>
<template #actions> <template #actions>
<div class="dashboard-chart-title-container"> <div class="dashboard-chart-title-container">
<t-date-range-picker <t-date-range-picker
@ -21,11 +26,16 @@
</t-card> </t-card>
</t-col> </t-col>
<t-col :xs="12" :xl="3"> <t-col :xs="12" :xl="3">
<t-card title="销售渠道" :subtitle="currentMonth" class="dashboard-chart-card" :bordered="false"> <t-card
:title="$t('pages.dashboardBase.topPanel.analysis.channels')"
:subtitle="currentMonth"
class="dashboard-chart-card"
:bordered="false"
>
<div <div
id="countContainer" id="countContainer"
:style="{ width: `${resizeTime * 326}px`, height: `${resizeTime * 326}px`, margin: '0 auto' }"
class="dashboard-chart-container" class="dashboard-chart-container"
:style="{ width: `${resizeTime * 326}px`, height: `${resizeTime * 326}px`, margin: '0 auto' }"
/> />
</t-card> </t-card>
</t-col> </t-col>

View File

@ -4,8 +4,8 @@
<t-col :xs="12" :xl="9"> <t-col :xs="12" :xl="9">
<t-card <t-card
:bordered="false" :bordered="false"
title="出入库概览" :title="$t('pages.dashboardBase.outputOverview.title')"
subtitle="(件)" :subtitle="$t('pages.dashboardBase.outputOverview.subtitle')"
:class="{ 'dashboard-overview-card': true, 'overview-panel': true }" :class="{ 'dashboard-overview-card': true, 'overview-panel': true }"
> >
<template #actions> <template #actions>
@ -23,26 +23,34 @@
<t-col :xs="12" :xl="3"> <t-col :xs="12" :xl="3">
<t-card :bordered="false" :class="{ 'dashboard-overview-card': true, 'export-panel': true }"> <t-card :bordered="false" :class="{ 'dashboard-overview-card': true, 'export-panel': true }">
<template #actions> <template #actions>
<t-button>导出数据</t-button> <t-button>{{ $t('pages.dashboardBase.outputOverview.export') }}</t-button>
</template> </template>
<t-row> <t-row>
<t-col :xs="6" :xl="12"> <t-col :xs="6" :xl="12">
<t-card :bordered="false" subtitle="本月出库总计(件)" class="inner-card"> <t-card
:bordered="false"
:subtitle="$t('pages.dashboardBase.outputOverview.month.input')"
class="inner-card"
>
<div class="inner-card__content"> <div class="inner-card__content">
<div class="inner-card__content-title">1726</div> <div class="inner-card__content-title">1726</div>
<div class="inner-card__content-footer"> <div class="inner-card__content-footer">
自从上周以来 {{ $t('pages.dashboardBase.outputOverview.since') }}
<trend class="trend-tag" type="down" :is-reverse-color="false" describe="20.3%" /> <trend class="trend-tag" type="down" :is-reverse-color="false" describe="20.3%" />
</div> </div>
</div> </div>
</t-card> </t-card>
</t-col> </t-col>
<t-col :xs="6" :xl="12"> <t-col :xs="6" :xl="12">
<t-card :bordered="false" subtitle="本月入库总计(件)" class="inner-card"> <t-card
:bordered="false"
:subtitle="$t('pages.dashboardBase.outputOverview.month.output')"
class="inner-card"
>
<div class="inner-card__content"> <div class="inner-card__content">
<div class="inner-card__content-title">226</div> <div class="inner-card__content-title">226</div>
<div class="inner-card__content-footer"> <div class="inner-card__content-footer">
自从上周以来 {{ $t('pages.dashboardBase.outputOverview.since') }}
<trend class="trend-tag" type="down" :is-reverse-color="false" describe="20.3%" /> <trend class="trend-tag" type="down" :is-reverse-color="false" describe="20.3%" />
</div> </div>
</div> </div>

View File

@ -1,11 +1,11 @@
<template> <template>
<t-row :gutter="16" class="row-container"> <t-row :gutter="16" class="row-container">
<t-col :xs="12" :xl="6"> <t-col :xs="12" :xl="6">
<t-card title="销售订单排名" class="dashboard-rank-card" :bordered="false"> <t-card :title="$t('pages.dashboardBase.rankList.title')" class="dashboard-rank-card" :bordered="false">
<template #actions> <template #actions>
<t-radio-group default-value="dateVal" variant="default-filled"> <t-radio-group default-value="dateVal" variant="default-filled">
<t-radio-button value="dateVal">本周</t-radio-button> <t-radio-button value="dateVal">{{ $t('pages.dashboardBase.rankList.week') }}</t-radio-button>
<t-radio-button value="monthVal">近三个月</t-radio-button> <t-radio-button value="monthVal">{{ $t('pages.dashboardBase.rankList.month') }}</t-radio-button>
</t-radio-group> </t-radio-group>
</template> </template>
<t-table :data="SALE_TEND_LIST" :columns="SALE_COLUMNS" row-key="productName"> <t-table :data="SALE_TEND_LIST" :columns="SALE_COLUMNS" row-key="productName">
@ -20,17 +20,19 @@
</span> </span>
</template> </template>
<template #operation="slotProps"> <template #operation="slotProps">
<t-link theme="primary" @click="rehandleClickOp(slotProps)">详情</t-link> <t-link theme="primary" @click="rehandleClickOp(slotProps)">{{
$t('pages.dashboardBase.rankList.info')
}}</t-link>
</template> </template>
</t-table> </t-table>
</t-card> </t-card>
</t-col> </t-col>
<t-col :xs="12" :xl="6"> <t-col :xs="12" :xl="6">
<t-card title="销售订单排名" class="dashboard-rank-card" :bordered="false"> <t-card :title="$t('pages.dashboardBase.rankList.title')" class="dashboard-rank-card" :bordered="false">
<template #actions> <template #actions>
<t-radio-group default-value="dateVal" variant="default-filled"> <t-radio-group default-value="dateVal" variant="default-filled">
<t-radio-button value="dateVal">本周</t-radio-button> <t-radio-button value="dateVal">{{ $t('pages.dashboardBase.rankList.week') }}</t-radio-button>
<t-radio-button value="monthVal">近三个月</t-radio-button> <t-radio-button value="monthVal">{{ $t('pages.dashboardBase.rankList.month') }}</t-radio-button>
</t-radio-group> </t-radio-group>
</template> </template>
<t-table :data="BUY_TEND_LIST" :columns="BUY_COLUMNS" row-key="productName"> <t-table :data="BUY_TEND_LIST" :columns="BUY_COLUMNS" row-key="productName">
@ -43,7 +45,9 @@
<trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" /> <trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" />
</template> </template>
<template #operation="slotProps"> <template #operation="slotProps">
<t-link theme="primary" @click="rehandleClickOp(slotProps)">详情</t-link> <t-link theme="primary" @click="rehandleClickOp(slotProps)">{{
$t('pages.dashboardBase.rankList.info')
}}</t-link>
</template> </template>
</t-table> </t-table>
</t-card> </t-card>
@ -52,10 +56,84 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// import type { TdBaseTableProps } from 'tdesign-vue-next';
import Trend from '@/components/trend/index.vue';
import { BUY_COLUMNS, BUY_TEND_LIST, SALE_COLUMNS, SALE_TEND_LIST } from '../constants'; import Trend from '@/components/trend/index.vue';
import { t } from '@/locales';
import { BUY_TEND_LIST, SALE_TEND_LIST } from '../constants';
const SALE_COLUMNS: TdBaseTableProps['columns'] = [
{
align: 'center',
colKey: 'index',
title: t('pages.dashboardBase.saleColumns.index'),
width: 70,
fixed: 'left',
},
{
align: 'left',
ellipsis: true,
colKey: 'productName',
title: t('pages.dashboardBase.saleColumns.productName'),
width: 150,
},
{
align: 'center',
colKey: 'growUp',
width: 70,
title: t('pages.dashboardBase.saleColumns.growUp'),
},
{
align: 'center',
colKey: 'count',
title: t('pages.dashboardBase.saleColumns.count'),
width: 70,
},
{
align: 'center',
colKey: 'operation',
title: t('pages.dashboardBase.saleColumns.operation'),
width: 70,
fixed: 'right',
},
];
const BUY_COLUMNS: TdBaseTableProps['columns'] = [
{
align: 'center',
colKey: 'index',
title: t('pages.dashboardBase.buyColumns.index'),
width: 70,
fixed: 'left',
},
{
align: 'left',
ellipsis: true,
colKey: 'productName',
width: 150,
title: t('pages.dashboardBase.buyColumns.productName'),
},
{
align: 'center',
colKey: 'growUp',
width: 70,
title: t('pages.dashboardBase.buyColumns.growUp'),
},
{
align: 'center',
colKey: 'count',
title: t('pages.dashboardBase.buyColumns.count'),
width: 70,
},
{
align: 'center',
colKey: 'operation',
title: t('pages.dashboardBase.buyColumns.operation'),
width: 70,
fixed: 'right',
},
];
const rehandleClickOp = (val: MouseEvent) => { const rehandleClickOp = (val: MouseEvent) => {
console.log(val); console.log(val);

View File

@ -32,7 +32,7 @@
<template #footer> <template #footer>
<div class="dashboard-item-bottom"> <div class="dashboard-item-bottom">
<div class="dashboard-item-block"> <div class="dashboard-item-block">
自从上周以来 {{ $t('pages.dashboardBase.topPanel.cardTips') }}
<trend <trend
class="dashboard-item-trend" class="dashboard-item-trend"
:type="item.upTrend ? 'up' : 'down'" :type="item.upTrend ? 'up' : 'down'"
@ -63,10 +63,10 @@ import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
// //
import Trend from '@/components/trend/index.vue'; import Trend from '@/components/trend/index.vue';
import { t } from '@/locales';
import { useSettingStore } from '@/store'; import { useSettingStore } from '@/store';
import { changeChartsTheme } from '@/utils/color'; import { changeChartsTheme } from '@/utils/color';
import { PANE_LIST } from '../constants';
import { constructInitDashboardDataset } from '../index'; import { constructInitDashboardDataset } from '../index';
echarts.use([LineChart, BarChart, CanvasRenderer]); echarts.use([LineChart, BarChart, CanvasRenderer]);
@ -74,6 +74,33 @@ echarts.use([LineChart, BarChart, CanvasRenderer]);
const store = useSettingStore(); const store = useSettingStore();
const resizeTime = ref(1); const resizeTime = ref(1);
const PANE_LIST = [
{
title: t('pages.dashboardBase.topPanel.card1'),
number: '¥ 28,425.00',
upTrend: '20.5%',
leftType: 'echarts-line',
},
{
title: t('pages.dashboardBase.topPanel.card2'),
number: '¥ 768.00',
downTrend: '20.5%',
leftType: 'echarts-bar',
},
{
title: t('pages.dashboardBase.topPanel.card3'),
number: '1126',
upTrend: '20.5%',
leftType: 'icon-usergroup',
},
{
title: t('pages.dashboardBase.topPanel.card4'),
number: 527,
downTrend: '20.5%',
leftType: 'icon-file-paste',
},
];
// moneyCharts // moneyCharts
let moneyContainer: HTMLElement; let moneyContainer: HTMLElement;
let moneyChart: echarts.ECharts; let moneyChart: echarts.ECharts;

View File

@ -1,13 +1,3 @@
import { TdBaseTableProps } from 'tdesign-vue-next';
interface DashboardPanel {
title: string;
number: string | number;
leftType: string;
upTrend?: string;
downTrend?: string;
}
interface TendItem { interface TendItem {
growUp?: number; growUp?: number;
productName: string; productName: string;
@ -15,33 +5,6 @@ interface TendItem {
date: string; date: string;
} }
export const PANE_LIST: Array<DashboardPanel> = [
{
title: '总收入',
number: '¥ 28,425.00',
upTrend: '20.5%',
leftType: 'echarts-line',
},
{
title: '总退款',
number: '¥ 768.00',
downTrend: '20.5%',
leftType: 'echarts-bar',
},
{
title: '活跃用户(个)',
number: '1126',
upTrend: '20.5%',
leftType: 'icon-usergroup',
},
{
title: '产生订单(个)',
number: 527,
downTrend: '20.5%',
leftType: 'icon-file-paste',
},
];
export const SALE_TEND_LIST: Array<TendItem> = [ export const SALE_TEND_LIST: Array<TendItem> = [
{ {
growUp: 1, growUp: 1,
@ -119,75 +82,3 @@ export const BUY_TEND_LIST: Array<TendItem> = [
date: '2021-09-12', date: '2021-09-12',
}, },
]; ];
export const SALE_COLUMNS: TdBaseTableProps['columns'] = [
{
align: 'center',
colKey: 'index',
title: '排名',
width: 70,
fixed: 'left',
},
{
align: 'left',
ellipsis: true,
colKey: 'productName',
title: '客户名称',
width: 150,
},
{
align: 'center',
colKey: 'growUp',
width: 70,
title: '较上周',
},
{
align: 'center',
colKey: 'count',
title: '订单量',
width: 70,
},
{
align: 'center',
colKey: 'operation',
title: '操作',
width: 70,
fixed: 'right',
},
];
export const BUY_COLUMNS: TdBaseTableProps['columns'] = [
{
align: 'center',
colKey: 'index',
title: '排名',
width: 70,
fixed: 'left',
},
{
align: 'left',
ellipsis: true,
colKey: 'productName',
width: 150,
title: '供应商名称',
},
{
align: 'center',
colKey: 'growUp',
width: 70,
title: '较上周',
},
{
align: 'center',
colKey: 'count',
title: '订单量',
width: 70,
},
{
align: 'center',
colKey: 'operation',
title: '操作',
width: 70,
fixed: 'right',
},
];

View File

@ -2,12 +2,14 @@ import dayjs from 'dayjs';
import { EChartsOption } from 'echarts'; import { EChartsOption } from 'echarts';
import { TChartColor } from '@/config/color'; import { TChartColor } from '@/config/color';
import { t } from '@/locales/index';
import { getRandomArray } from '@/utils/charts'; import { getRandomArray } from '@/utils/charts';
import { getChartListColor } from '@/utils/color'; import { getChartListColor } from '@/utils/color';
/** 首页 dashboard 折线图 */ /** 首页 dashboard 折线图 */
export function constructInitDashboardDataset(type: string) { export function constructInitDashboardDataset(type: string) {
const dateArray: Array<string> = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; const dateArray: Array<string> = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const datasetAxis = { const datasetAxis = {
xAxis: { xAxis: {
type: 'category', type: 'category',
@ -162,16 +164,16 @@ export function constructInitDataset({
left: 'center', left: 'center',
bottom: '0', bottom: '0',
orient: 'horizontal', orient: 'horizontal',
data: ['本月', '上月'], data: [t('pages.dashboardBase.chart.thisMonth'), t('pages.dashboardBase.chart.lastMonth')],
}, },
series: [ series: [
{ {
name: '本月', name: t('pages.dashboardBase.chart.thisMonth'),
data: outArray, data: outArray,
type: 'bar', type: 'bar',
}, },
{ {
name: '上月', name: t('pages.dashboardBase.chart.lastMonth'),
data: inArray, data: inArray,
type: 'bar', type: 'bar',
}, },
@ -231,7 +233,7 @@ export function getLineChartDataSet({
left: 'center', left: 'center',
bottom: '0', bottom: '0',
orient: 'horizontal', // legend 横向布局。 orient: 'horizontal', // legend 横向布局。
data: ['本月', '上月'], data: [t('pages.dashboardBase.chart.thisMonth'), t('pages.dashboardBase.chart.lastMonth')],
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
color: placeholderColor, color: placeholderColor,
@ -263,7 +265,7 @@ export function getLineChartDataSet({
}, },
series: [ series: [
{ {
name: '本月', name: t('pages.dashboardBase.chart.thisMonth'),
data: outArray, data: outArray,
type: 'line', type: 'line',
smooth: false, smooth: false,
@ -279,7 +281,7 @@ export function getLineChartDataSet({
}, },
}, },
{ {
name: '上月', name: t('pages.dashboardBase.chart.lastMonth'),
data: inArray, data: inArray,
type: 'line', type: 'line',
smooth: false, smooth: false,
@ -347,7 +349,7 @@ export function getPieChartDataSet({
label: { label: {
show: true, show: true,
position: 'center', position: 'center',
formatter: ['{value|{d}%}', '{name|{b}渠道占比}'].join('\n'), formatter: ['{value|{d}%}', '{name|{b}}'].join('\n'),
rich: { rich: {
value: { value: {
color: textColor, color: textColor,
@ -388,9 +390,9 @@ export function getPieChartDataSet({
data: [ data: [
{ {
value: 1048, value: 1048,
name: '线上', name: t('pages.dashboardBase.topPanel.analysis.channel1'),
}, },
{ value: radius * 7, name: '门店' }, { value: radius * 7, name: t('pages.dashboardBase.topPanel.analysis.channel2') },
], ],
}, },
], ],

View File

@ -1,32 +1,34 @@
import { t } from '@/locales';
export const PANE_LIST_DATA = [ export const PANE_LIST_DATA = [
{ {
title: '总申请数(次)', title: t('pages.dashboardDetail.topPanel.paneList.totalRequest'),
number: '1126', number: '1126',
upTrend: '10%', upTrend: '10%',
}, },
{ {
title: '供应商数量(个)', title: t('pages.dashboardDetail.topPanel.paneList.suppliers'),
number: '13', number: '13',
downTrend: '13%', downTrend: '13%',
}, },
{ {
title: '采购商品品类(类)', title: t('pages.dashboardDetail.topPanel.paneList.productCategory'),
number: '4', number: '4',
upTrend: '10%', upTrend: '10%',
}, },
{ {
title: '申请人数量(人)', title: t('pages.dashboardDetail.topPanel.paneList.applicant'),
number: 90, number: 90,
downTrend: '44%', downTrend: '44%',
leftType: 'icon-file-paste', leftType: 'icon-file-paste',
}, },
{ {
title: '申请完成率(%', title: t('pages.dashboardDetail.topPanel.paneList.completionRate'),
number: 80.5, number: 80.5,
upTrend: '70%', upTrend: '70%',
}, },
{ {
title: '到货及时率(%', title: t('pages.dashboardDetail.topPanel.paneList.arrivalRate'),
number: 78, number: 78,
upTrend: '16%', upTrend: '16%',
}, },
@ -34,17 +36,17 @@ export const PANE_LIST_DATA = [
export const PRODUCT_LIST = [ export const PRODUCT_LIST = [
{ {
description: 'SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部', description: t('pages.dashboardDetail.sslDescription'),
index: 1, index: 1,
isSetup: true, isSetup: true,
name: 'SSL证书', name: t('pages.dashboardDetail.ssl'),
type: 4, type: 4,
}, },
{ {
description: 'SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部', description: t('pages.dashboardDetail.sslDescription'),
index: 1, index: 1,
isSetup: true, isSetup: true,
name: 'SSL证书', name: t('pages.dashboardDetail.ssl'),
type: 4, type: 4,
}, },
]; ];

View File

@ -1,9 +1,9 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { TChartColor } from '@/config/color'; import { TChartColor } from '@/config/color';
import { t } from '@/locales';
import { getDateArray, getRandomArray } from '@/utils/charts'; import { getDateArray, getRandomArray } from '@/utils/charts';
import { getChartListColor } from '@/utils/color'; import { getChartListColor } from '@/utils/color';
/** /**
* *
* *
@ -54,7 +54,6 @@ export function getScatterDataSet({
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
// splitLine: { show: false},
axisLabel: { axisLabel: {
color: placeholderColor, color: placeholderColor,
}, },
@ -89,7 +88,10 @@ export function getScatterDataSet({
left: 'center', left: 'center',
bottom: '0', bottom: '0',
orient: 'horizontal', // legend 横向布局。 orient: 'horizontal', // legend 横向布局。
data: ['按摩仪', '咖啡机'], data: [
t(`pages.dashboardDetail.procurement.goods.massageMachine`),
t(`pages.dashboardDetail.procurement.goods.coffeeMachine`),
],
itemHeight: 8, itemHeight: 8,
itemWidth: 8, itemWidth: 8,
textStyle: { textStyle: {
@ -99,13 +101,13 @@ export function getScatterDataSet({
}, },
series: [ series: [
{ {
name: '按摩仪', name: t(`pages.dashboardDetail.procurement.goods.massageMachine`),
symbolSize: 10, symbolSize: 10,
data: outArray.reverse(), data: outArray.reverse(),
type: 'scatter', type: 'scatter',
}, },
{ {
name: '咖啡机', name: t(`pages.dashboardDetail.procurement.goods.coffeeMachine`),
symbolSize: 10, symbolSize: 10,
data: inArray.concat(inArray.reverse()), data: inArray.concat(inArray.reverse()),
type: 'scatter', type: 'scatter',
@ -120,7 +122,10 @@ export function getFolderLineDataSet({
placeholderColor, placeholderColor,
borderColor, borderColor,
}: { dateTime?: Array<string> } & TChartColor) { }: { dateTime?: Array<string> } & TChartColor) {
let dateArray: Array<string> = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; let dateArray = [];
for (let i = 1; i < 7; i++) {
dateArray.push(t(`pages.dashboardDetail.chart.week${i}`));
}
if (dateTime.length > 0) { if (dateTime.length > 0) {
const divideNum = 7; const divideNum = 7;
dateArray = getDateArray(dateTime, divideNum); dateArray = getDateArray(dateTime, divideNum);
@ -137,7 +142,12 @@ export function getFolderLineDataSet({
left: 'center', left: 'center',
bottom: '0', bottom: '0',
orient: 'horizontal', // legend 横向布局。 orient: 'horizontal', // legend 横向布局。
data: ['杯子', '茶叶', '蜂蜜', '面粉'], data: [
t(`pages.dashboardDetail.procurement.goods.cup`),
t(`pages.dashboardDetail.procurement.goods.tea`),
t(`pages.dashboardDetail.procurement.goods.honey`),
t(`pages.dashboardDetail.procurement.goods.flour`),
],
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
color: placeholderColor, color: placeholderColor,
@ -176,7 +186,7 @@ export function getFolderLineDataSet({
showSymbol: true, showSymbol: true,
symbol: 'circle', symbol: 'circle',
symbolSize: 8, symbolSize: 8,
name: '杯子', name: t(`pages.dashboardDetail.procurement.goods.cup`),
stack: '总量', stack: '总量',
data: [ data: [
getRandomArray(), getRandomArray(),
@ -197,7 +207,7 @@ export function getFolderLineDataSet({
showSymbol: true, showSymbol: true,
symbol: 'circle', symbol: 'circle',
symbolSize: 8, symbolSize: 8,
name: '茶叶', name: t(`pages.dashboardDetail.procurement.goods.tea`),
stack: '总量', stack: '总量',
data: [ data: [
getRandomArray(), getRandomArray(),
@ -218,7 +228,7 @@ export function getFolderLineDataSet({
showSymbol: true, showSymbol: true,
symbol: 'circle', symbol: 'circle',
symbolSize: 8, symbolSize: 8,
name: '蜂蜜', name: t(`pages.dashboardDetail.procurement.goods.honey`),
stack: '总量', stack: '总量',
data: [ data: [
getRandomArray(), getRandomArray(),
@ -239,7 +249,7 @@ export function getFolderLineDataSet({
showSymbol: true, showSymbol: true,
symbol: 'circle', symbol: 'circle',
symbolSize: 8, symbolSize: 8,
name: '面粉', name: t(`pages.dashboardDetail.procurement.goods.flour`),
stack: '总量', stack: '总量',
data: [ data: [
getRandomArray(), getRandomArray(),

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="dashboard-panel-detail"> <div class="dashboard-panel-detail">
<t-card title="本月采购申请情况" class="dashboard-detail-card" :bordered="false"> <t-card :title="$t('pages.dashboardDetail.topPanel.title')" class="dashboard-detail-card" :bordered="false">
<t-row :gutter="[16, 16]"> <t-row :gutter="[16, 16]">
<t-col v-for="(item, index) in PANE_LIST_DATA" :key="index" :xs="6" :xl="3"> <t-col v-for="(item, index) in PANE_LIST_DATA" :key="index" :xs="6" :xl="3">
<t-card class="dashboard-list-card" :description="item.title"> <t-card class="dashboard-list-card" :description="item.title">
<div class="dashboard-list-card__number">{{ item.number }}</div> <div class="dashboard-list-card__number">{{ item.number }}</div>
<div class="dashboard-list-card__text"> <div class="dashboard-list-card__text">
<div class="dashboard-list-card__text-left"> <div class="dashboard-list-card__text-left">
环比 {{ $t('pages.dashboardDetail.topPanel.quarter') }}
<trend class="icon" :type="item.upTrend ? 'up' : 'down'" :describe="item.upTrend || item.downTrend" /> <trend class="icon" :type="item.upTrend ? 'up' : 'down'" :describe="item.upTrend || item.downTrend" />
</div> </div>
<t-icon name="chevron-right" /> <t-icon name="chevron-right" />
@ -18,7 +18,7 @@
</t-card> </t-card>
<t-row :gutter="[16, 16]" class="row-margin"> <t-row :gutter="[16, 16]" class="row-margin">
<t-col :xs="12" :xl="9"> <t-col :xs="12" :xl="9">
<t-card class="dashboard-detail-card" title="采购商品申请趋势" subtitle="(件)" :bordered="false"> <t-card class="dashboard-detail-card" :title="$t('pages.dashboardDetail.procurement.title')" :bordered="false">
<template #actions> <template #actions>
<t-date-range-picker <t-date-range-picker
class="card-date-picker-container" class="card-date-picker-container"
@ -41,7 +41,11 @@
/> />
</t-col> </t-col>
</t-row> </t-row>
<t-card :class="['dashboard-detail-card', 'row-margin']" title="采购商品满意度分布" :bordered="false"> <t-card
:class="['dashboard-detail-card', 'row-margin']"
:title="$t('pages.dashboardDetail.satisfaction.title')"
:bordered="false"
>
<template #actions> <template #actions>
<t-date-range-picker <t-date-range-picker
class="card-date-picker-container" class="card-date-picker-container"
@ -51,7 +55,7 @@
style="display: inline-block; margin-right: var(--td-comp-margin-s); width: 248px" style="display: inline-block; margin-right: var(--td-comp-margin-s); width: 248px"
@change="onSatisfyChange" @change="onSatisfyChange"
/> />
<t-button class="card-date-button"> 导出数据 </t-button> <t-button class="card-date-button"> {{ $t('pages.dashboardDetail.satisfaction.export') }} </t-button>
</template> </template>
<div id="scatterContainer" style="width: 100%; height: 434px" /> <div id="scatterContainer" style="width: 100%; height: 434px" />
</t-card> </t-card>
@ -258,6 +262,7 @@ const onMaterialChange = (value: string[]) => {
.t-icon { .t-icon {
font-size: var(--td-comp-size-xxxs); font-size: var(--td-comp-size-xxxs);
} }
&-left { &-left {
display: flex; display: flex;

View File

@ -1,11 +1,13 @@
import { t } from '@/locales';
export const BASE_INFO_DATA = [ export const BASE_INFO_DATA = [
{ {
name: '合同名称', name: t('constants.contract.name'),
value: '总部办公用品采购项目', value: '总部办公用品采购项目',
type: null, type: null,
}, },
{ {
name: '合同状态', name: t('constants.contract.status'),
value: '履行中', value: '履行中',
type: { type: {
key: 'contractStatus', key: 'contractStatus',
@ -13,52 +15,52 @@ export const BASE_INFO_DATA = [
}, },
}, },
{ {
name: '合同编号', name: t('constants.contract.num'),
value: 'BH00010', value: 'BH00010',
type: null, type: null,
}, },
{ {
name: '合同类型', name: t('constants.contract.type'),
value: '主合同', value: t('constants.contract.typeOptions.main'),
type: null, type: null,
}, },
{ {
name: '合同收付类型', name: t('constants.contract.payType'),
value: '付款', value: t('constants.contract.pay'),
type: null, type: null,
}, },
{ {
name: '合同金额', name: t('constants.contract.amount'),
value: '5,000,000', value: '¥ 5,000,000',
type: null, type: null,
}, },
{ {
name: '甲方', name: t('constants.contract.company'),
value: '腾讯科技(深圳)有限公司', value: '腾讯科技(深圳)有限公司',
type: null, type: null,
}, },
{ {
name: '乙方', name: t('constants.contract.employee'),
value: '欧尚', value: '欧尚',
type: null, type: null,
}, },
{ {
name: '合同签订日期', name: t('constants.contract.signDate'),
value: '2020-12-20', value: '2020-12-20',
type: null, type: null,
}, },
{ {
name: '合同生效日期', name: t('constants.contract.effectiveDate'),
value: '2021-01-20', value: '2021-01-20',
type: null, type: null,
}, },
{ {
name: '合同结束日期', name: t('constants.contract.endDate'),
value: '2022-12-20', value: '2022-12-20',
type: null, type: null,
}, },
{ {
name: '合同附件', name: t('constants.contract.attachment'),
value: '总部办公用品采购项目合同.pdf', value: '总部办公用品采购项目合同.pdf',
type: { type: {
key: 'contractAnnex', key: 'contractAnnex',
@ -66,68 +68,17 @@ export const BASE_INFO_DATA = [
}, },
}, },
{ {
name: '备注', name: t('constants.contract.remark'),
value: '--', value: '--',
type: null, type: null,
}, },
{ {
name: '创建时间', name: t('constants.contract.createDate'),
value: '2020-12-22 10:00:00', value: '2020-12-22 10:00:00',
type: null, type: null,
}, },
]; ];
export const TABLE_COLUMNS_DATA = [
{
width: 280,
ellipsis: true,
colKey: 'index',
title: '申请号',
sorter: (a: any, b: any) => a.index.substr(3) - b.index.substr(3),
},
{
width: 200,
ellipsis: true,
colKey: 'pdName',
title: '产品名称',
sorter: (a: any, b: any) => a.pdName.length - b.pdName.length,
},
{
width: 200,
ellipsis: true,
colKey: 'pdNum',
title: '产品编号',
},
{
width: 160,
ellipsis: true,
colKey: 'purchaseNum',
title: '采购数量',
sorter: (a: any, b: any) => a.purchaseNum - b.purchaseNum,
},
{
width: 160,
ellipsis: true,
colKey: 'adminName',
title: '申请部门',
},
{
width: 200,
ellipsis: true,
colKey: 'updateTime',
title: '创建时间',
sorter: (a: any, b: any) => Date.parse(a.updateTime) - Date.parse(b.updateTime),
},
{
align: 'left' as const,
fixed: 'right' as const,
width: 200,
className: 'test2',
colKey: 'op',
title: '操作',
},
];
export const PRODUCT_LIST = [ export const PRODUCT_LIST = [
{ {
name: 'MacBook Pro 2021', name: 'MacBook Pro 2021',

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="detail-advanced"> <div class="detail-advanced">
<t-card title="基本信息" :bordered="false"> <t-card :title="$t('pages.detailCard.baseInfo.title')" :bordered="false">
<div class="info-block"> <div class="info-block">
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item"> <div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
<h1>{{ item.name }}</h1> <h1>{{ item.name }}</h1>
@ -18,23 +18,32 @@
</t-card> </t-card>
<!-- 发票进度 --> <!-- 发票进度 -->
<t-card title="发票进度" class="container-base-margin-top" :bordered="false"> <t-card :title="$t('pages.detailCard.invoice.title')" class="container-base-margin-top" :bordered="false">
<t-row justify="space-between"> <t-row justify="space-between">
<t-steps :current="updateCurrent"> <t-steps :current="updateCurrent">
<t-step-item title="申请提交" content="已于12月21日提交" /> <t-step-item
<t-step-item title="电子发票" content="预计13个工作日" /> :title="$t('pages.detailCard.invoice.step1.title')"
<t-step-item title="发票已邮寄" content="电子发票开出后7个工作日联系" /> :content="$t('pages.detailCard.invoice.step1.content')"
<t-step-item title="完成" content="" /> />
<t-step-item
:title="$t('pages.detailCard.invoice.step2.title')"
:content="$t('pages.detailCard.invoice.step2.content')"
/>
<t-step-item
:title="$t('pages.detailCard.invoice.step3.title')"
:content="$t('pages.detailCard.invoice.step3.content')"
/>
<t-step-item :title="$t('pages.detailCard.invoice.step4.title')" />
</t-steps> </t-steps>
</t-row> </t-row>
</t-card> </t-card>
<!-- 产品目录 --> <!-- 产品目录 -->
<t-card title="产品目录" class="container-base-margin-top" :bordered="false"> <t-card :title="$t('pages.detailCard.product.title')" class="container-base-margin-top" :bordered="false">
<template #actions> <template #actions>
<t-radio-group default-value="dateVal"> <t-radio-group default-value="dateVal">
<t-radio-button value="dateVal"> 季度 </t-radio-button> <t-radio-button value="dateVal"> {{ $t('pages.detailCard.product.quarter') }} </t-radio-button>
<t-radio-button value="monthVal"> 月份 </t-radio-button> <t-radio-button value="monthVal"> {{ $t('pages.detailCard.product.month') }} </t-radio-button>
</t-radio-group> </t-radio-group>
</template> </template>
<t-row :gutter="16" class="product-block-container"> <t-row :gutter="16" class="product-block-container">
@ -42,7 +51,7 @@
<div class="product-add"> <div class="product-add">
<div class="product-sub"> <div class="product-sub">
<t-icon name="add" class="product-sub-icon" /> <t-icon name="add" class="product-sub-icon" />
<span>新增产品</span> <span>{{ $t('pages.detailCard.product.add') }}</span>
</div> </div>
</div> </div>
</t-col> </t-col>
@ -53,7 +62,7 @@
</t-card> </t-card>
<!-- 产品采购明细 --> <!-- 产品采购明细 -->
<t-card title="产品采购明细" class="container-base-margin-top" :bordered="false"> <t-card :title="$t('pages.detailCard.detail.title')" class="container-base-margin-top" :bordered="false">
<t-table <t-table
:columns="columns" :columns="columns"
:data="data" :data="data"
@ -88,8 +97,10 @@
<template #op="slotProps"> <template #op="slotProps">
<t-space> <t-space>
<t-link theme="primary" @click="listClick()">管理</t-link> <t-link theme="primary" @click="listClick()">{{ t('pages.detailCard.detail.form.manage') }}</t-link>
<t-link theme="danger" @click="deleteClickOp(slotProps)">删除</t-link> <t-link theme="danger" @click="deleteClickOp(slotProps)">{{
t('pages.detailCard.detail.form.delete')
}}</t-link>
</t-space> </t-space>
</template> </template>
@ -99,7 +110,7 @@
</t-table> </t-table>
</t-card> </t-card>
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm"> <t-dialog v-model:visible="visible" :header="$t('pages.detailCard.baseInfo.title')" @confirm="onConfirm">
<template #body> <template #body>
<div class="dialog-info-block"> <div class="dialog-info-block">
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item"> <div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
@ -130,9 +141,61 @@ export default {
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { getPurchaseList } from '@/api/detail'; import { getPurchaseList } from '@/api/detail';
import { t } from '@/locales';
import Product from './components/Product.vue'; import Product from './components/Product.vue';
import { BASE_INFO_DATA, PRODUCT_LIST, TABLE_COLUMNS_DATA as columns } from './constants'; import { BASE_INFO_DATA, PRODUCT_LIST } from './constants';
const columns = [
{
width: 280,
ellipsis: true,
colKey: 'index',
title: t('pages.detailCard.detail.form.applyNo'),
sorter: (a: any, b: any) => a.index.substr(3) - b.index.substr(3),
},
{
width: 200,
ellipsis: true,
colKey: 'pdName',
title: t('pages.detailCard.detail.form.product'),
sorter: (a: any, b: any) => a.pdName.length - b.pdName.length,
},
{
width: 200,
ellipsis: true,
colKey: 'pdNum',
title: t('pages.detailCard.detail.form.productNo'),
},
{
width: 160,
ellipsis: true,
colKey: 'purchaseNum',
title: t('pages.detailCard.detail.form.num'),
sorter: (a: any, b: any) => a.purchaseNum - b.purchaseNum,
},
{
width: 160,
ellipsis: true,
colKey: 'adminName',
title: t('pages.detailCard.detail.form.department'),
},
{
width: 200,
ellipsis: true,
colKey: 'updateTime',
title: t('pages.detailCard.detail.form.createTime'),
sorter: (a: any, b: any) => Date.parse(a.updateTime) - Date.parse(b.updateTime),
},
{
align: 'left' as const,
fixed: 'right' as const,
width: 200,
className: 'test2',
colKey: 'op',
title: t('pages.detailCard.detail.form.operation'),
},
];
const data = ref([]); const data = ref([]);
const pagination = ref({ const pagination = ref({

View File

@ -1,78 +0,0 @@
export const BASE_INFO_DATA = [
{
name: '合同名称',
value: '总部办公用品采购项目',
type: null,
},
{
name: '合同状态',
value: '履行中',
type: {
key: 'contractStatus',
value: 'inProgress',
},
},
{
name: '合同编号',
value: 'BH00010',
type: null,
},
{
name: '合同类型',
value: '主合同',
type: null,
},
{
name: '合同收付类型',
value: '付款',
type: null,
},
{
name: '合同金额',
value: '5,000,000元',
type: null,
},
{
name: '甲方',
value: '腾讯科技(深圳)有限公司',
type: null,
},
{
name: '乙方',
value: '欧尚',
type: null,
},
{
name: '合同签订日期',
value: '2020-12-20',
type: null,
},
{
name: '合同生效日期',
value: '2021-01-20',
type: null,
},
{
name: '合同结束日期',
value: '2022-12-20',
type: null,
},
{
name: '合同附件',
value: '总部办公用品采购项目合同.pdf',
type: {
key: 'contractAnnex',
value: 'pdf',
},
},
{
name: '备注',
value: '--',
type: null,
},
{
name: '创建时间',
value: '2020-12-22 10:00:00',
type: null,
},
];

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="detail-base"> <div class="detail-base">
<t-card title="基本信息" :bordered="false"> <t-card :title="$t('pages.detailBase.baseInfo.title')" :bordered="false">
<div class="info-block"> <div class="info-block">
<div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item"> <div v-for="(item, index) in BASE_INFO_DATA" :key="index" class="info-item">
<h1>{{ item.name }}</h1> <h1>{{ item.name }}</h1>
@ -17,11 +17,20 @@
</div> </div>
</t-card> </t-card>
<t-card title="变更记录" class="container-base-margin-top" :bordered="false"> <t-card :title="$t('pages.detailBase.changelog.title')" class="container-base-margin-top" :bordered="false">
<t-steps class="detail-base-info-steps" layout="vertical" theme="dot" :current="1"> <t-steps class="detail-base-info-steps" layout="vertical" theme="dot" :current="1">
<t-step-item title="上传合同附件" content="这里是提示文字" /> <t-step-item
<t-step-item title="修改合同金额" content="这里是提示文字" /> :title="$t('pages.detailBase.changelog.step1.title')"
<t-step-item title="新建合同" content="2020-12-01 15:00:00 管理员-李川操作" /> :content="$t('pages.detailBase.changelog.step1.subtitle')"
/>
<t-step-item
:title="$t('pages.detailBase.changelog.step2.title')"
:content="$t('pages.detailBase.changelog.step2.subtitle')"
/>
<t-step-item
:title="$t('pages.detailBase.changelog.step3.title')"
:content="$t('pages.detailBase.changelog.step3.desc')"
/>
</t-steps> </t-steps>
</t-card> </t-card>
</div> </div>
@ -34,14 +43,16 @@ export default {
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
import { t } from '@/locales';
const BASE_INFO_DATA = [ const BASE_INFO_DATA = [
{ {
name: '合同名称', name: t('constants.contract.name'),
value: '总部办公用品采购项目', value: '总部办公用品采购项目',
type: null, type: null,
}, },
{ {
name: '合同状态', name: t('constants.contract.status'),
value: '履行中', value: '履行中',
type: { type: {
key: 'contractStatus', key: 'contractStatus',
@ -49,52 +60,52 @@ const BASE_INFO_DATA = [
}, },
}, },
{ {
name: '合同编号', name: t('constants.contract.num'),
value: 'BH00010', value: 'BH00010',
type: null, type: null,
}, },
{ {
name: '合同类型', name: t('constants.contract.type'),
value: '主合同', value: t('constants.contract.typeOptions.main'),
type: null, type: null,
}, },
{ {
name: '合同收付类型', name: t('constants.contract.payType'),
value: '付款', value: t('constants.contract.pay'),
type: null, type: null,
}, },
{ {
name: '合同金额', name: t('constants.contract.amount'),
value: '5,000,000', value: '¥ 5,000,000',
type: null, type: null,
}, },
{ {
name: '甲方', name: t('constants.contract.company'),
value: '腾讯科技(深圳)有限公司', value: '腾讯科技(深圳)有限公司',
type: null, type: null,
}, },
{ {
name: '乙方', name: t('constants.contract.employee'),
value: '欧尚', value: '欧尚',
type: null, type: null,
}, },
{ {
name: '合同签订日期', name: t('constants.contract.signDate'),
value: '2020-12-20', value: '2020-12-20',
type: null, type: null,
}, },
{ {
name: '合同生效日期', name: t('constants.contract.effectiveDate'),
value: '2021-01-20', value: '2021-01-20',
type: null, type: null,
}, },
{ {
name: '合同结束日期', name: t('constants.contract.endDate'),
value: '2022-12-20', value: '2022-12-20',
type: null, type: null,
}, },
{ {
name: '合同附件', name: t('constants.contract.attachment'),
value: '总部办公用品采购项目合同.pdf', value: '总部办公用品采购项目合同.pdf',
type: { type: {
key: 'contractAnnex', key: 'contractAnnex',
@ -102,12 +113,7 @@ const BASE_INFO_DATA = [
}, },
}, },
{ {
name: '备注', name: t('constants.contract.createDate'),
value: '--',
type: null,
},
{
name: '创建时间',
value: '2020-12-22 10:00:00', value: '2020-12-22 10:00:00',
type: null, type: null,
}, },
@ -115,5 +121,5 @@ const BASE_INFO_DATA = [
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import url('./index.less'); @import './index.less';
</style> </style>

View File

@ -80,36 +80,3 @@ export const BASE_INFO_DATA = [
type: null, type: null,
}, },
]; ];
export const TABLE_COLUMNS = [
{
width: '280',
ellipsis: true,
colKey: 'name',
title: '项目名称',
sorter: (a: any, b: any) => a.name.substr(10) - b.name.substr(10),
},
{
width: '280',
ellipsis: true,
colKey: 'adminName',
title: '管理员',
},
{
width: '280',
className: 'test',
ellipsis: true,
colKey: 'updateTime',
title: '创建时间',
sorter: (a: any, b: any) => Date.parse(a.updateTime) - Date.parse(b.updateTime),
},
{
align: 'left' as const,
width: '200',
className: 'test2',
ellipsis: true,
colKey: 'op',
fixed: 'right' as const,
title: '操作',
},
];

View File

@ -1,4 +1,5 @@
import { TChartColor } from '@/config/color'; import { TChartColor } from '@/config/color';
import { t } from '@/locales/index';
import { getDateArray, getRandomArray } from '@/utils/charts'; import { getDateArray, getRandomArray } from '@/utils/charts';
import { getChartListColor } from '@/utils/color'; import { getChartListColor } from '@/utils/color';
@ -52,7 +53,7 @@ export function getSmoothLineDataSet({
}, },
}, },
legend: { legend: {
data: ['本月', '上月'], data: [t('pages.detailDeploy.deployTrend.thisMonth'), t('pages.detailDeploy.deployTrend.lastMonth')],
icon: 'circle', icon: 'circle',
bottom: '0', bottom: '0',
itemGap: 48, itemGap: 48,
@ -65,7 +66,7 @@ export function getSmoothLineDataSet({
}, },
series: [ series: [
{ {
name: '上月', name: t('pages.detailDeploy.deployTrend.lastMonth'),
data: [ data: [
getRandomArray(), getRandomArray(),
getRandomArray(), getRandomArray(),
@ -86,7 +87,7 @@ export function getSmoothLineDataSet({
}, },
}, },
{ {
name: '本月', name: t('pages.detailDeploy.deployTrend.thisMonth'),
data: [ data: [
getRandomArray(), getRandomArray(),
getRandomArray(), getRandomArray(),
@ -129,6 +130,11 @@ export function get2ColBarChartDataSet({
thisYearListCopy = thisYearListCopy.reverse(); thisYearListCopy = thisYearListCopy.reverse();
} }
const data = [];
for (let i = 1; i < 7; i++) {
data.push(t(`pages.detailDeploy.deployTrend.week${i}`));
}
return { return {
color: getChartListColor(), color: getChartListColor(),
tooltip: { tooltip: {
@ -144,7 +150,7 @@ export function get2ColBarChartDataSet({
xAxis: [ xAxis: [
{ {
type: 'category', type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], data,
axisTick: { axisTick: {
alignWithLabel: true, alignWithLabel: true,
}, },
@ -173,7 +179,7 @@ export function get2ColBarChartDataSet({
}, },
], ],
legend: { legend: {
data: ['去年', '今年'], data: [t('pages.detailDeploy.deployTrend.lastYear'), t('pages.detailDeploy.deployTrend.thisYear')],
bottom: '0', bottom: '0',
icon: 'rect', icon: 'rect',
itemGap: 48, itemGap: 48,
@ -186,7 +192,7 @@ export function get2ColBarChartDataSet({
}, },
series: [ series: [
{ {
name: '去年', name: t('pages.detailDeploy.deployTrend.lastYear'),
type: 'bar', type: 'bar',
barWidth: '30%', barWidth: '30%',
data: lastYearListCopy, data: lastYearListCopy,
@ -195,7 +201,7 @@ export function get2ColBarChartDataSet({
}, },
}, },
{ {
name: '今年', name: t('pages.detailDeploy.deployTrend.thisYear'),
type: 'bar', type: 'bar',
barWidth: '30%', barWidth: '30%',
data: thisYearListCopy, data: thisYearListCopy,

View File

@ -2,18 +2,18 @@
<div class="detail-deploy"> <div class="detail-deploy">
<t-row :gutter="16"> <t-row :gutter="16">
<t-col :lg="6" :xs="12"> <t-col :lg="6" :xs="12">
<t-card title="部署趋势" :bordered="false"> <t-card :title="$t('pages.detailDeploy.deployTrend.title')" :bordered="false">
<div class="deploy-panel-left"> <div class="deploy-panel-left">
<div id="monitorContainer" style="width: 100%; height: 265px" /> <div id="monitorContainer" style="width: 100%; height: 265px" />
</div> </div>
</t-card> </t-card>
</t-col> </t-col>
<t-col :lg="6" :xs="12"> <t-col :lg="6" :xs="12">
<t-card title="告警情况" :bordered="false"> <t-card :title="$t('pages.detailDeploy.deployTrend.warning')" :bordered="false">
<template #actions> <template #actions>
<t-radio-group default-value="dateVal" @change="onAlertChange"> <t-radio-group default-value="dateVal" @change="onAlertChange">
<t-radio-button value="dateVal"> 本周 </t-radio-button> <t-radio-button value="dateVal"> {{ $t('pages.detailDeploy.deployTrend.thisWeek') }} </t-radio-button>
<t-radio-button value="monthVal"> 本月 </t-radio-button> <t-radio-button value="monthVal"> {{ $t('pages.detailDeploy.deployTrend.thisMonth') }} </t-radio-button>
</t-radio-group> </t-radio-group>
</template> </template>
<div id="dataContainer" style="width: 100%; height: 265px" /> <div id="dataContainer" style="width: 100%; height: 265px" />
@ -22,7 +22,7 @@
</t-row> </t-row>
<!-- 项目列表 --> <!-- 项目列表 -->
<t-card title="项目列表" class="container-base-margin-top" :bordered="false"> <t-card :title="$t('pages.detailDeploy.projectList.title')" class="container-base-margin-top" :bordered="false">
<t-table <t-table
:columns="columns" :columns="columns"
:data="data" :data="data"
@ -41,8 +41,12 @@
</template> </template>
<template #op="slotProps"> <template #op="slotProps">
<t-space> <t-space>
<t-link theme="primary" @click="listClick()">管理</t-link> <t-link theme="primary" @click="listClick()">{{
<t-link theme="danger" @click="deleteClickOp(slotProps)">删除</t-link> $t('pages.detailDeploy.projectList.table.manage')
}}</t-link>
<t-link theme="danger" @click="deleteClickOp(slotProps)">{{
$t('pages.detailDeploy.projectList.table.delete')
}}</t-link>
</t-space> </t-space>
</template> </template>
<template #op-column> <template #op-column>
@ -51,7 +55,11 @@
</t-table> </t-table>
</t-card> </t-card>
<t-dialog v-model:visible="visible" header="基本信息" @confirm="onConfirm"> <t-dialog
v-model:visible="visible"
:header="$t('pages.detailDeploy.projectList.dialog.title')"
@confirm="onConfirm"
>
<template #body> <template #body>
<div class="dialog-info-block"> <div class="dialog-info-block">
<div class="dialog-info-block"> <div class="dialog-info-block">
@ -86,12 +94,46 @@ import { CanvasRenderer } from 'echarts/renderers';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'; import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { getProjectList } from '@/api/detail'; import { getProjectList } from '@/api/detail';
import { t } from '@/locales';
import { useSettingStore } from '@/store'; import { useSettingStore } from '@/store';
import { changeChartsTheme } from '@/utils/color'; import { changeChartsTheme } from '@/utils/color';
import { BASE_INFO_DATA, TABLE_COLUMNS as columns } from './constants'; import { BASE_INFO_DATA } from './constants';
import { get2ColBarChartDataSet, getSmoothLineDataSet } from './index'; import { get2ColBarChartDataSet, getSmoothLineDataSet } from './index';
const columns = [
{
width: '280',
ellipsis: true,
colKey: 'name',
title: t('pages.detailDeploy.projectList.table.name'),
sorter: (a: any, b: any) => a.name.substr(10) - b.name.substr(10),
},
{
width: '280',
ellipsis: true,
title: t('pages.detailDeploy.projectList.table.admin'),
colKey: 'adminName',
},
{
width: '280',
className: 'test',
ellipsis: true,
colKey: 'updateTime',
title: t('pages.detailDeploy.projectList.table.createTime'),
sorter: (a: any, b: any) => Date.parse(a.updateTime) - Date.parse(b.updateTime),
},
{
align: 'left' as const,
width: '200',
className: 'test2',
ellipsis: true,
colKey: 'op',
fixed: 'right' as const,
title: t('pages.detailDeploy.projectList.table.operation'),
},
];
echarts.use([ echarts.use([
TitleComponent, TitleComponent,
ToolboxComponent, ToolboxComponent,

View File

@ -18,14 +18,14 @@
<t-tooltip <t-tooltip
class="set-read-icon" class="set-read-icon"
:overlay-style="{ margin: '6px' }" :overlay-style="{ margin: '6px' }"
:content="item.status ? '设为已读' : '设为未读'" :content="item.status ? $t('pages.detailSecondary.setRead') : $t('pages.detailSecondary.setUnread')"
> >
<span class="msg-action-icon" @click="setReadStatus(item)"> <span class="msg-action-icon" @click="setReadStatus(item)">
<t-icon v-if="!!item.status" name="queue" size="16px" /> <t-icon v-if="!!item.status" name="queue" size="16px" />
<t-icon v-else name="chat" /> <t-icon v-else name="chat" />
</span> </span>
</t-tooltip> </t-tooltip>
<t-tooltip content="删除通知" :overlay-style="{ margin: '6px' }"> <t-tooltip :content="t('pages.detailSecondary.delete')" :overlay-style="{ margin: '6px' }">
<span @click="handleClickDeleteBtn(item)"> <span @click="handleClickDeleteBtn(item)">
<t-icon name="delete" size="16px" /> <t-icon name="delete" size="16px" />
</span> </span>
@ -36,7 +36,7 @@
</t-list> </t-list>
<div v-else class="secondary-msg-list__empty-list"> <div v-else class="secondary-msg-list__empty-list">
<empty-icon></empty-icon> <empty-icon></empty-icon>
<p>暂无通知</p> <p>{{ t('pages.detailSecondary.empty') }}</p>
</div> </div>
</t-tab-panel> </t-tab-panel>
</t-tabs> </t-tabs>
@ -62,20 +62,21 @@ import { computed, ref } from 'vue';
import EmptyIcon from '@/assets/assets-empty.svg?component'; import EmptyIcon from '@/assets/assets-empty.svg?component';
import { NOTIFICATION_TYPES } from '@/constants'; import { NOTIFICATION_TYPES } from '@/constants';
import { t } from '@/locales';
import { useNotificationStore } from '@/store'; import { useNotificationStore } from '@/store';
import type { NotificationItem } from '@/types/interface'; import type { NotificationItem } from '@/types/interface';
const TAB_LIST = [ const TAB_LIST = [
{ {
label: '全部通知', label: t('pages.detailSecondary.all'),
value: 'msgData', value: 'msgData',
}, },
{ {
label: '未读通知', label: t('pages.detailSecondary.unread'),
value: 'unreadMsg', value: 'unreadMsg',
}, },
{ {
label: '已读通知', label: t('pages.detailSecondary.read'),
value: 'readMsg', value: 'readMsg',
}, },
]; ];
@ -124,5 +125,5 @@ const deleteMsg = () => {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import url('./index.less'); @import './index.less';
</style> </style>

View File

@ -27,19 +27,19 @@ export const INITIAL_DATA = {
}; };
export const TYPE_OPTIONS = [ export const TYPE_OPTIONS = [
{ label: '类型A', value: '1' }, { label: 'Type A', value: '1' },
{ label: '类型B', value: '2' }, { label: 'Type B', value: '2' },
{ label: '类型C', value: '3' }, { label: 'Type C', value: '3' },
]; ];
export const PARTY_A_OPTIONS = [ export const PARTY_A_OPTIONS = [
{ label: '公司A', value: '1' }, { label: 'Company A', value: '1' },
{ label: '公司B', value: '2' }, { label: 'Company B', value: '2' },
{ label: '公司C', value: '3' }, { label: 'Company C', value: '3' },
]; ];
export const PARTY_B_OPTIONS = [ export const PARTY_B_OPTIONS = [
{ label: '公司A', value: '1' }, { label: 'Company A', value: '1' },
{ label: '公司B', value: '2' }, { label: 'Company B', value: '2' },
{ label: '公司C', value: '3' }, { label: 'Company C', value: '3' },
]; ];

View File

@ -11,25 +11,19 @@
> >
<div class="form-basic-container"> <div class="form-basic-container">
<div class="form-basic-item"> <div class="form-basic-item">
<div class="form-basic-container-title">合同信息</div> <div class="form-basic-container-title">{{ $t('pages.formBase.title') }}</div>
<!-- 表单内容 --> <!-- 表单内容 -->
<!-- 合同名称,合同类型 --> <!-- 合同名称,合同类型 -->
<t-row class="row-gap" :gutter="[32, 24]"> <t-row class="row-gap" :gutter="[32, 24]">
<t-col :span="6"> <t-col :span="6">
<t-form-item label="合同名称" name="name"> <t-form-item :label="$t('pages.formBase.contractName')" name="name">
<t-input v-model="formData.name" :style="{ width: '322px' }" placeholder="请输入内容" /> <t-input v-model="formData.name" :style="{ width: '322px' }" placeholder="请输入内容" />
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="6"> <t-col :span="6">
<t-form-item label="合同类型" name="type"> <t-form-item :label="$t('pages.formBase.contractType')" name="type">
<t-select <t-select v-model="formData.type" :style="{ width: '322px' }" class="demo-select-base" clearable>
v-model="formData.type"
:style="{ width: '322px' }"
placeholder="请选择类型"
class="demo-select-base"
clearable
>
<t-option v-for="(item, index) in TYPE_OPTIONS" :key="index" :value="item.value" :label="item.label"> <t-option v-for="(item, index) in TYPE_OPTIONS" :key="index" :value="item.value" :label="item.label">
{{ item.label }} {{ item.label }}
</t-option> </t-option>
@ -39,25 +33,25 @@
<!-- 合同收付类型 --> <!-- 合同收付类型 -->
<t-col :span="8"> <t-col :span="8">
<t-form-item label="合同收付类型" name="payment"> <t-form-item :label="$t('pages.formBase.contractPayType')" name="payment">
<t-radio-group v-model="formData.payment"> <t-radio-group v-model="formData.payment">
<t-radio value="1"> 收款 </t-radio> <t-radio value="1"> {{ $t('pages.formBase.receive') }} </t-radio>
<t-radio value="2"> 付款 </t-radio> <t-radio value="2"> {{ $t('pages.formBase.pay') }} </t-radio>
</t-radio-group> </t-radio-group>
<span class="space-item" /> <span class="space-item" />
<div> <div>
<t-input placeholder="请输入金额" :style="{ width: '160px' }" /> <t-input :placeholder="$t('pages.formBase.contractAmountPlaceholder')" :style="{ width: '160px' }" />
</div> </div>
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="6"> <t-col :span="6">
<t-form-item label="甲方" name="partyA"> <t-form-item :label="$t('pages.formBase.company')" name="partyA">
<t-select <t-select
v-model="formData.partyA" v-model="formData.partyA"
:style="{ width: '322px' }" :style="{ width: '322px' }"
class="demo-select-base" class="demo-select-base"
placeholder="请选择类型" :placeholder="$t('pages.formBase.contractTypePlaceholder')"
clearable clearable
> >
<t-option v-for="(item, index) in PARTY_A_OPTIONS" :key="index" :value="item.value" :label="item.label"> <t-option v-for="(item, index) in PARTY_A_OPTIONS" :key="index" :value="item.value" :label="item.label">
@ -67,11 +61,11 @@
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="6"> <t-col :span="6">
<t-form-item label="乙方" name="partyB"> <t-form-item :label="$t('pages.formBase.employee')" name="partyB">
<t-select <t-select
v-model="formData.partyB" v-model="formData.partyB"
:style="{ width: '322px' }" :style="{ width: '322px' }"
placeholder="请选择类型" :placeholder="$t('pages.formBase.contractTypePlaceholder')"
class="demo-select-base" class="demo-select-base"
clearable clearable
> >
@ -82,7 +76,7 @@
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="6"> <t-col :span="6">
<t-form-item label="合同签订日期" name="signDate"> <t-form-item :label="$t('pages.formBase.contractSignDate')" name="signDate">
<t-date-picker <t-date-picker
v-model="formData.signDate" v-model="formData.signDate"
:style="{ width: '322px' }" :style="{ width: '322px' }"
@ -93,7 +87,7 @@
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="6"> <t-col :span="6">
<t-form-item label="合同生效日期" name="startDate"> <t-form-item :label="$t('pages.formBase.contractEffectiveDate')" name="startDate">
<t-date-picker <t-date-picker
v-model="formData.startDate" v-model="formData.startDate"
:style="{ width: '322px' }" :style="{ width: '322px' }"
@ -104,7 +98,7 @@
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="6"> <t-col :span="6">
<t-form-item label="合同结束日期" name="endDate"> <t-form-item :label="$t('pages.formBase.contractEndDate')" name="endDate">
<t-date-picker <t-date-picker
v-model="formData.endDate" v-model="formData.endDate"
:style="{ width: '322px' }" :style="{ width: '322px' }"
@ -115,28 +109,30 @@
</t-form-item> </t-form-item>
</t-col> </t-col>
<t-col :span="6"> <t-col :span="6">
<t-form-item label="上传文件" name="files"> <t-form-item :label="$t('pages.formBase.upload')" name="files">
<t-upload <t-upload
v-model="formData.files" v-model="formData.files"
action="https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo" action="https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
tips="请上传pdf文件大小在60M以内" :tips="$t('pages.formBase.uploadTips')"
:size-limit="{ size: 60, unit: 'MB' }" :size-limit="{ size: 60, unit: 'MB' }"
:format-response="formatResponse" :format-response="formatResponse"
:before-upload="beforeUpload" :before-upload="beforeUpload"
@fail="handleFail" @fail="handleFail"
> >
<t-button class="form-submit-upload-btn" variant="outline"> 上传合同文件 </t-button> <t-button class="form-submit-upload-btn" variant="outline">
{{ $t('pages.formBase.uploadFile') }}
</t-button>
</t-upload> </t-upload>
</t-form-item> </t-form-item>
</t-col> </t-col>
</t-row> </t-row>
<div class="form-basic-container-title form-title-gap">其它信息</div> <div class="form-basic-container-title form-title-gap">{{ $t('pages.formBase.otherInfo') }}</div>
<t-form-item label="备注" name="comment"> <t-form-item :label="$t('pages.formBase.remark')" name="comment">
<t-textarea v-model="formData.comment" :height="124" placeholder="请输入备注" /> <t-textarea v-model="formData.comment" :height="124" :placeholder="$t('pages.formBase.remarkPlaceholder')" />
</t-form-item> </t-form-item>
<t-form-item label="公证人"> <t-form-item :label="$t('pages.formBase.notaryPublic')">
<t-avatar-group> <t-avatar-group>
<t-avatar>D</t-avatar> <t-avatar>D</t-avatar>
<t-avatar>S</t-avatar> <t-avatar>S</t-avatar>
@ -149,8 +145,12 @@
<div class="form-submit-container"> <div class="form-submit-container">
<div class="form-submit-sub"> <div class="form-submit-sub">
<div class="form-submit-left"> <div class="form-submit-left">
<t-button theme="primary" class="form-submit-confirm" type="submit"> 确认提交 </t-button> <t-button theme="primary" class="form-submit-confirm" type="submit">
<t-button type="reset" class="form-submit-cancel" theme="default" variant="base"> 取消 </t-button> {{ $t('pages.formBase.confirm') }}
</t-button>
<t-button type="reset" class="form-submit-cancel" theme="default" variant="base">
{{ $t('pages.formBase.cancel') }}
</t-button>
</div> </div>
</div> </div>
</div> </div>
@ -201,5 +201,5 @@ const formatResponse = (res: any) => {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import url('./index.less'); @import './index.less';
</style> </style>

View File

@ -1,26 +1,26 @@
import { FormRule } from 'tdesign-vue-next'; import { FormRule } from 'tdesign-vue-next';
export const FORM_RULES: Record<string, FormRule[]> = { export const FORM_RULES: Record<string, FormRule[]> = {
name: [{ required: true, message: '请选择合同名称', type: 'error' }], name: [{ required: true, type: 'error' }],
type: [{ required: true, message: '请选择发票类型', type: 'error' }], type: [{ required: true, type: 'error' }],
title: [{ required: true, message: '请输入发票抬头', type: 'error' }], title: [{ required: true, type: 'error' }],
taxNum: [{ required: true, message: '请输入纳税人识别号', type: 'error' }], taxNum: [{ required: true, type: 'error' }],
consignee: [{ required: true, message: '请输入收货人', type: 'error' }], consignee: [{ required: true, type: 'error' }],
mobileNum: [{ required: true, message: '请输入手机号码', type: 'error' }], mobileNum: [{ required: true, type: 'error' }],
deliveryAddress: [{ required: true, message: '请选择收货地址', type: 'error' }], deliveryAddress: [{ required: true, type: 'error' }],
fullAddress: [{ required: true, message: '请输入详细地址', type: 'error' }], fullAddress: [{ required: true, type: 'error' }],
}; };
export const NAME_OPTIONS = [ export const NAME_OPTIONS = [
{ label: '合同A', value: '1' }, { label: 'A', value: '1' },
{ label: '合同B', value: '2' }, { label: 'B', value: '2' },
{ label: '合同C', value: '3' }, { label: 'C', value: '3' },
]; ];
export const TYPE_OPTIONS = [ export const TYPE_OPTIONS = [
{ label: '类型A', value: '1' }, { label: 'Type A', value: '1' },
{ label: '类型B', value: '2' }, { label: 'Type B', value: '2' },
{ label: '类型C', value: '3' }, { label: 'Type C', value: '3' },
]; ];
export const ADDRESS_OPTIONS = [ export const ADDRESS_OPTIONS = [

View File

@ -4,22 +4,22 @@
<!-- 简单步骤条 --> <!-- 简单步骤条 -->
<t-card :bordered="false"> <t-card :bordered="false">
<t-steps class="step-container" :current="1" status="process"> <t-steps class="step-container" :current="1" status="process">
<t-step-item title="提交申请" content="已于12月21日提交" /> <t-step-item :title="$t('pages.formStep.step1.title')" :content="$t('pages.formStep.step1.subtitle')" />
<t-step-item title="电子信息" content="预计1-3个工作日" /> <t-step-item :title="$t('pages.formStep.step2.title')" :content="$t('pages.formStep.step2.subtitle')" />
<t-step-item title="发票已邮寄" content="电子发票开出后联系" /> <t-step-item :title="$t('pages.formStep.step3.title')" :content="$t('pages.formStep.step3.subtitle')" />
<t-step-item title="完成申请" content="如有疑问联系客服" /> <t-step-item :title="$t('pages.formStep.step4.title')" :content="$t('pages.formStep.step4.subtitle')" />
</t-steps> </t-steps>
</t-card> </t-card>
<!-- 分步表单1 --> <!-- 分步表单1 -->
<div v-show="activeForm === 0" class="rule-tips"> <div v-show="activeForm === 0" class="rule-tips">
<t-alert theme="info" title="发票开具规则:" :close="true"> <t-alert theme="info" :title="$t('pages.formStep.step1.rules')" :close="true">
<template #message> <template #message>
<p> <p>
1申请开票后电子发票在13个工作日内开具增值税专用发票纸质如资质审核通过将在电子发票开具后10个工作日内为您寄出 {{ $t('pages.formStep.step1.rule1') }}
</p> </p>
<p>2开票金额为您实际支付金额</p> <p>{{ $t('pages.formStep.step1.rule2') }}</p>
<p>3如有疑问请直接联系13300001111</p> <p>{{ $t('pages.formStep.step1.rule3') }}</p>
</template> </template>
</t-alert> </t-alert>
</div> </div>
@ -31,23 +31,23 @@
label-align="right" label-align="right"
@submit="(result: SubmitContext) => onSubmit(result, 1)" @submit="(result: SubmitContext) => onSubmit(result, 1)"
> >
<t-form-item label="合同名称" name="name"> <t-form-item :label="$t('pages.formStep.step1.contractName')" name="name">
<t-select v-model="formData1.name" :style="{ width: '480px' }" class="demo-select-base" clearable> <t-select v-model="formData1.name" :style="{ width: '480px' }" class="demo-select-base" clearable>
<t-option v-for="(item, index) in NAME_OPTIONS" :key="index" :value="item.value" :label="item.label"> <t-option v-for="(item, index) in NAME_OPTIONS" :key="index" :value="item.value" :label="item.label">
{{ item.label }} {{ item.label }}
</t-option> </t-option>
</t-select> </t-select>
</t-form-item> </t-form-item>
<t-form-item label="发票类型" name="type"> <t-form-item :label="$t('pages.formStep.step1.invoiceType')" name="type">
<t-select v-model="formData1.type" :style="{ width: '480px' }" class="demo-select-base" clearable> <t-select v-model="formData1.type" :style="{ width: '480px' }" class="demo-select-base" clearable>
<t-option v-for="(item, index) in TYPE_OPTIONS" :key="index" :value="item.value" :label="item.label"> <t-option v-for="(item, index) in TYPE_OPTIONS" :key="index" :value="item.value" :label="item.label">
{{ item.label }} {{ item.label }}
</t-option> </t-option>
</t-select> </t-select>
</t-form-item> </t-form-item>
<t-form-item label="开票金额"> {{ amount }} </t-form-item> <t-form-item :label="$t('pages.formStep.step1.amount')"> ¥ {{ amount }} </t-form-item>
<t-form-item> <t-form-item>
<t-button theme="primary" type="submit"> 提交申请 </t-button> <t-button theme="primary" type="submit"> {{ $t('pages.formStep.step1.submit') }} </t-button>
</t-form-item> </t-form-item>
</t-form> </t-form>
@ -61,30 +61,58 @@
@reset="onReset(0)" @reset="onReset(0)"
@submit="(result: SubmitContext) => onSubmit(result, 2)" @submit="(result: SubmitContext) => onSubmit(result, 2)"
> >
<t-form-item label="发票抬头" name="title"> <t-form-item :label="$t('pages.formStep.step2.invoiceTitle')" name="title">
<t-input v-model="formData2.title" :style="{ width: '480px' }" placeholder="请输入发票抬头" /> <t-input
v-model="formData2.title"
:style="{ width: '480px' }"
:placeholder="$t('pages.formStep.step2.invoiceTitlePlaceholder')"
/>
</t-form-item> </t-form-item>
<t-form-item label="纳税人识别号" name="taxNum"> <t-form-item :label="$t('pages.formStep.step2.taxNum')" name="taxNum">
<t-input v-model="formData2.taxNum" :style="{ width: '480px' }" placeholder="请输入纳税人识别号" /> <t-input
v-model="formData2.taxNum"
:style="{ width: '480px' }"
:placeholder="$t('pages.formStep.step2.taxNumPlaceholder')"
/>
</t-form-item> </t-form-item>
<t-form-item label="单位地址" name="address"> <t-form-item :label="$t('pages.formStep.step2.address')" name="address">
<t-input v-model="formData2.address" :style="{ width: '480px' }" placeholder="请输入单位地址" /> <t-input
v-model="formData2.address"
:style="{ width: '480px' }"
:placeholder="$t('pages.formStep.step2.addressPlaceholder')"
/>
</t-form-item> </t-form-item>
<t-form-item label="开户行" name="bank"> <t-form-item :label="$t('pages.formStep.step2.bank')" name="bank">
<t-input v-model="formData2.bank" :style="{ width: '480px' }" placeholder="请输入开户行" /> <t-input
v-model="formData2.bank"
:style="{ width: '480px' }"
:placeholder="$t('pages.formStep.step2.bankPlaceholder')"
/>
</t-form-item> </t-form-item>
<t-form-item label="银行账号" name="bankAccount"> <t-form-item :label="$t('pages.formStep.step2.bankAccount')" name="bankAccount">
<t-input v-model="formData2.bankAccount" :style="{ width: '480px' }" placeholder="请输入银行账号" /> <t-input
v-model="formData2.bankAccount"
:style="{ width: '480px' }"
:placeholder="$t('pages.formStep.step2.bankAccountPlaceholder')"
/>
</t-form-item> </t-form-item>
<t-form-item label="通知邮箱" name="email"> <t-form-item :label="$t('pages.formStep.step2.email')" name="email">
<t-input v-model="formData2.email" :style="{ width: '480px' }" placeholder="请输入通知邮箱" /> <t-input
v-model="formData2.email"
:style="{ width: '480px' }"
:placeholder="$t('pages.formStep.step2.emailPlaceholder')"
/>
</t-form-item> </t-form-item>
<t-form-item label="通知手机" name="tel"> <t-form-item :label="$t('pages.formStep.step2.tel')" name="tel">
<t-input v-model="formData2.tel" :style="{ width: '480px' }" placeholder="请输入通知手机" /> <t-input
v-model="formData2.tel"
:style="{ width: '480px' }"
:placeholder="$t('pages.formStep.step2.telPlaceholder')"
/>
</t-form-item> </t-form-item>
<t-form-item> <t-form-item>
<t-button type="reset" theme="default" variant="base"> 上一步 </t-button> <t-button type="reset" theme="default" variant="base"> {{ $t('pages.formStep.preStep') }} </t-button>
<t-button theme="primary" type="submit"> 下一步 </t-button> <t-button theme="primary" type="submit"> {{ $t('pages.formStep.nextStep') }} </t-button>
</t-form-item> </t-form-item>
</t-form> </t-form>
@ -98,43 +126,41 @@
@reset="onReset(1)" @reset="onReset(1)"
@submit="(result: SubmitContext) => onSubmit(result, 6)" @submit="(result: SubmitContext) => onSubmit(result, 6)"
> >
<t-form-item label="收货人" name="consignee"> <t-form-item :label="$t('pages.formStep.step3.consignee')" name="consignee">
<t-input v-model="formData3.consignee" :style="{ width: '480px' }" placeholder="请输入收货人" /> <t-input v-model="formData3.consignee" :style="{ width: '480px' }" />
</t-form-item> </t-form-item>
<t-form-item label="手机号码" name="mobileNum"> <t-form-item :label="$t('pages.formStep.step3.mobileNum')" name="mobileNum">
<t-input v-model="formData3.mobileNum" :style="{ width: '480px' }" placeholder="请输入手机号码" /> <t-input v-model="formData3.mobileNum" :style="{ width: '480px' }" />
</t-form-item> </t-form-item>
<t-form-item label="收货地址" name="deliveryAddress"> <t-form-item :label="$t('pages.formStep.step3.deliveryAddress')" name="deliveryAddress">
<t-select <t-select v-model="formData3.deliveryAddress" :style="{ width: '480px' }" class="demo-select-base" clearable>
v-model="formData3.deliveryAddress"
:style="{ width: '480px' }"
placeholder="请选择收货地址"
class="demo-select-base"
clearable
>
<t-option v-for="(item, index) in ADDRESS_OPTIONS" :key="index" :value="item.value" :label="item.label"> <t-option v-for="(item, index) in ADDRESS_OPTIONS" :key="index" :value="item.value" :label="item.label">
{{ item.label }} {{ item.label }}
</t-option> </t-option>
</t-select> </t-select>
</t-form-item> </t-form-item>
<t-form-item label="详细地址" name="fullAddress"> <t-form-item :label="$t('pages.formStep.step3.fullAddress')" name="fullAddress">
<t-textarea v-model="formData3.fullAddress" :style="{ width: '480px' }" placeholder="请输入详细地址" /> <t-textarea v-model="formData3.fullAddress" :style="{ width: '480px' }" />
</t-form-item> </t-form-item>
<t-form-item> <t-form-item>
<t-button type="reset" theme="default" variant="base"> 上一步 </t-button> <t-button type="reset" theme="default" variant="base"> {{ $t('pages.formStep.preStep') }} </t-button>
<t-button theme="primary" type="submit"> 下一步 </t-button> <t-button theme="primary" type="submit"> {{ $t('pages.formStep.nextStep') }} </t-button>
</t-form-item> </t-form-item>
</t-form> </t-form>
<!-- 分步表单4 --> <!-- 分步表单4 -->
<div v-show="activeForm === 6" class="step-form-4"> <div v-show="activeForm === 6" class="step-form-4">
<t-icon name="check-circle-filled" style="color: green" size="52px" /> <t-space direction="vertical" style="align-items: center">
<p class="text">完成开票申请</p> <t-icon name="check-circle-filled" style="color: green" size="52px" />
<p class="tips">预计13个工作日会将电子发票发至邮箱发票邮寄请耐心等待</p> <p class="text">{{ $t('pages.formStep.step4.finishTitle') }}</p>
<div class="button-group"> <p class="tips">{{ $t('pages.formStep.step4.finishTips') }}</p>
<t-button theme="primary" @click="onReset(0)"> 再次申请 </t-button> <div class="button-group">
<t-button variant="base" theme="default" @click="complete"> 查看进度 </t-button> <t-button theme="primary" @click="onReset(0)"> {{ $t('pages.formStep.step4.reapply') }} </t-button>
</div> <t-button variant="base" theme="default" @click="complete">
{{ $t('pages.formStep.step4.check') }}
</t-button>
</div>
</t-space>
</div> </div>
</div> </div>
</div> </div>
@ -194,5 +220,5 @@ const complete = () => {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import url('./index.less'); @import './index.less';
</style> </style>

View File

@ -1,44 +0,0 @@
import { PrimaryTableCol, TableRowData } from 'tdesign-vue-next';
export const COLUMNS: PrimaryTableCol<TableRowData>[] = [
{ colKey: 'row-select', type: 'multiple', width: 64, fixed: 'left' },
{
title: '合同名称',
align: 'left',
width: 320,
colKey: 'name',
fixed: 'left',
},
{ title: '合同状态', colKey: 'status', width: 160 },
{
title: '合同编号',
width: 160,
ellipsis: true,
colKey: 'no',
},
{
title: '合同类型',
width: 160,
ellipsis: true,
colKey: 'contractType',
},
{
title: '合同收付类型',
width: 160,
ellipsis: true,
colKey: 'paymentType',
},
{
title: '合同金额 (元)',
width: 160,
ellipsis: true,
colKey: 'amount',
},
{
align: 'left',
fixed: 'right',
width: 160,
colKey: 'op',
title: '操作',
},
];

View File

@ -3,12 +3,16 @@
<t-card class="list-card-container" :bordered="false"> <t-card class="list-card-container" :bordered="false">
<t-row justify="space-between"> <t-row justify="space-between">
<div class="left-operation-container"> <div class="left-operation-container">
<t-button @click="handleSetupContract"> 新建合同 </t-button> <t-button @click="handleSetupContract"> {{ $t('pages.listBase.create') }} </t-button>
<t-button variant="base" theme="default" :disabled="!selectedRowKeys.length"> 导出合同 </t-button> <t-button variant="base" theme="default" :disabled="!selectedRowKeys.length">
<p v-if="!!selectedRowKeys.length" class="selected-count">已选{{ selectedRowKeys.length }}</p> {{ $t('pages.listBase.export') }}</t-button
>
<p v-if="!!selectedRowKeys.length" class="selected-count">
{{ $t('pages.listBase.select') }} {{ selectedRowKeys.length }} {{ $t('pages.listBase.items') }}
</p>
</div> </div>
<div class="search-input"> <div class="search-input">
<t-input v-model="searchValue" placeholder="请输入你需要搜索的内容" clearable> <t-input v-model="searchValue" :placeholder="$t('pages.listBase.placeholder')" clearable>
<template #suffix-icon> <template #suffix-icon>
<search-icon size="16px" /> <search-icon size="16px" />
</template> </template>
@ -30,30 +34,42 @@
@select-change="rehandleSelectChange" @select-change="rehandleSelectChange"
> >
<template #status="{ row }"> <template #status="{ row }">
<t-tag v-if="row.status === CONTRACT_STATUS.FAIL" theme="danger" variant="light"> 审核失败 </t-tag> <t-tag v-if="row.status === CONTRACT_STATUS.FAIL" theme="danger" variant="light">
<t-tag v-if="row.status === CONTRACT_STATUS.AUDIT_PENDING" theme="warning" variant="light"> 待审核 </t-tag> {{ $t('pages.listBase.contractStatusEnum.fail') }}</t-tag
<t-tag v-if="row.status === CONTRACT_STATUS.EXEC_PENDING" theme="warning" variant="light"> 待履行 </t-tag> >
<t-tag v-if="row.status === CONTRACT_STATUS.EXECUTING" theme="success" variant="light"> 履行中 </t-tag> <t-tag v-if="row.status === CONTRACT_STATUS.AUDIT_PENDING" theme="warning" variant="light">
<t-tag v-if="row.status === CONTRACT_STATUS.FINISH" theme="success" variant="light"> 已完成 </t-tag> {{ $t('pages.listBase.contractStatusEnum.audit') }}
</t-tag>
<t-tag v-if="row.status === CONTRACT_STATUS.EXEC_PENDING" theme="warning" variant="light">
{{ $t('pages.listBase.contractStatusEnum.pending') }}
</t-tag>
<t-tag v-if="row.status === CONTRACT_STATUS.EXECUTING" theme="success" variant="light">
{{ $t('pages.listBase.contractStatusEnum.executing') }}
</t-tag>
<t-tag v-if="row.status === CONTRACT_STATUS.FINISH" theme="success" variant="light">
{{ $t('pages.listBase.contractStatusEnum.finish') }}
</t-tag>
</template> </template>
<template #contractType="{ row }"> <template #contractType="{ row }">
<p v-if="row.contractType === CONTRACT_TYPES.MAIN">审核失败</p> <p v-if="row.contractType === CONTRACT_TYPES.MAIN">{{ $t('pages.listBase.contractStatusEnum.fail') }}</p>
<p v-if="row.contractType === CONTRACT_TYPES.SUB">待审核</p> <p v-if="row.contractType === CONTRACT_TYPES.SUB">{{ $t('pages.listBase.contractStatusEnum.audit') }}</p>
<p v-if="row.contractType === CONTRACT_TYPES.SUPPLEMENT">待履行</p> <p v-if="row.contractType === CONTRACT_TYPES.SUPPLEMENT">
{{ $t('pages.listBase.contractStatusEnum.pending') }}
</p>
</template> </template>
<template #paymentType="{ row }"> <template #paymentType="{ row }">
<div v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.PAYMENT" class="payment-col"> <div v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.PAYMENT" class="payment-col">
付款<trend class="dashboard-item-trend" type="up" /> {{ $t('pages.listBase.pay') }}<trend class="dashboard-item-trend" type="up" />
</div> </div>
<div v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.RECEIPT" class="payment-col"> <div v-if="row.paymentType === CONTRACT_PAYMENT_TYPES.RECEIPT" class="payment-col">
收款<trend class="dashboard-item-trend" type="down" /> {{ $t('pages.listBase.receive') }}<trend class="dashboard-item-trend" type="down" />
</div> </div>
</template> </template>
<template #op="slotProps"> <template #op="slotProps">
<t-space> <t-space>
<t-link theme="primary" @click="handleClickDetail()">详情</t-link> <t-link theme="primary" @click="handleClickDetail()"> {{ $t('pages.listBase.detail') }}</t-link>
<t-link theme="danger" @click="handleClickDelete(slotProps)">删除</t-link> <t-link theme="danger" @click="handleClickDelete(slotProps)"> {{ $t('pages.listBase.delete') }}</t-link>
</t-space> </t-space>
</template> </template>
</t-table> </t-table>
@ -77,7 +93,7 @@ export default {
<script setup lang="ts"> <script setup lang="ts">
import { SearchIcon } from 'tdesign-icons-vue-next'; import { SearchIcon } from 'tdesign-icons-vue-next';
import { MessagePlugin } from 'tdesign-vue-next'; import { MessagePlugin, PrimaryTableCol, TableRowData } from 'tdesign-vue-next';
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
@ -85,12 +101,54 @@ import { getList } from '@/api/list';
import Trend from '@/components/trend/index.vue'; import Trend from '@/components/trend/index.vue';
import { prefix } from '@/config/global'; import { prefix } from '@/config/global';
import { CONTRACT_PAYMENT_TYPES, CONTRACT_STATUS, CONTRACT_TYPES } from '@/constants'; import { CONTRACT_PAYMENT_TYPES, CONTRACT_STATUS, CONTRACT_TYPES } from '@/constants';
import { t } from '@/locales';
import { useSettingStore } from '@/store'; import { useSettingStore } from '@/store';
import { COLUMNS } from './constants';
const store = useSettingStore(); const store = useSettingStore();
const COLUMNS: PrimaryTableCol<TableRowData>[] = [
{ colKey: 'row-select', type: 'multiple', width: 64, fixed: 'left' },
{
title: t('pages.listBase.contractName'),
align: 'left',
width: 320,
colKey: 'name',
fixed: 'left',
},
{ title: t('pages.listBase.contractStatus'), colKey: 'status', width: 160 },
{
title: t('pages.listBase.contractNum'),
width: 160,
ellipsis: true,
colKey: 'no',
},
{
title: t('pages.listBase.contractType'),
width: 160,
ellipsis: true,
colKey: 'contractType',
},
{
title: t('pages.listBase.contractPayType'),
width: 160,
ellipsis: true,
colKey: 'paymentType',
},
{
title: t('pages.listBase.contractAmount'),
width: 160,
ellipsis: true,
colKey: 'amount',
},
{
title: t('pages.listBase.operation'),
align: 'left',
fixed: 'right',
width: 160,
colKey: 'op',
},
];
const data = ref([]); const data = ref([]);
const pagination = ref({ const pagination = ref({
defaultPageSize: 20, defaultPageSize: 20,

View File

@ -1,29 +1,29 @@
<template> <template>
<t-dialog v-model:visible="formVisible" header="新建产品" :width="680" :footer="false"> <t-dialog v-model:visible="formVisible" :header="$t('pages.listCard.create')" :width="680" :footer="false">
<template #body> <template #body>
<!-- 表单内容 --> <!-- 表单内容 -->
<t-form ref="form" :data="formData" :rules="rules" :label-width="100" @submit="onSubmit"> <t-form ref="form" :data="formData" :rules="rules" :label-width="100" @submit="onSubmit">
<t-form-item label="产品名称" name="name"> <t-form-item :label="$t('pages.listCard.productName')" name="name">
<t-input v-model="formData.name" :style="{ width: '480px' }" placeholder="请输入产品名称" /> <t-input v-model="formData.name" :style="{ width: '480px' }" />
</t-form-item> </t-form-item>
<t-form-item label="产品状态" name="status"> <t-form-item :label="$t('pages.listCard.productStatus')" name="status">
<t-radio-group v-model="formData.status"> <t-radio-group v-model="formData.status">
<t-radio value="0">已停用</t-radio> <t-radio value="0">{{ $t('pages.listCard.productStatusEnum.off') }}</t-radio>
<t-radio value="1">已启用</t-radio> <t-radio value="1">{{ $t('pages.listCard.productStatusEnum.on') }}</t-radio>
</t-radio-group> </t-radio-group>
</t-form-item> </t-form-item>
<t-form-item label="产品描述" name="description"> <t-form-item :label="$t('pages.listCard.productDescription')" name="description">
<t-input v-model="formData.description" :style="{ width: '480px' }" placeholder="请输入产品描述" /> <t-input v-model="formData.description" :style="{ width: '480px' }" />
</t-form-item> </t-form-item>
<t-form-item label="产品类型" name="type"> <t-form-item :label="$t('pages.listCard.productType')" name="type">
<t-select v-model="formData.type" clearable :style="{ width: '480px' }"> <t-select v-model="formData.type" clearable :style="{ width: '480px' }">
<t-option v-for="(item, index) in SELECT_OPTIONS" :key="index" :value="item.value" :label="item.label"> <t-option v-for="(item, index) in SELECT_OPTIONS" :key="index" :value="item.value" :label="item.label">
{{ item.label }} {{ item.label }}
</t-option> </t-option>
</t-select> </t-select>
</t-form-item> </t-form-item>
<t-form-item label="备注" name="mark"> <t-form-item :label="$t('pages.listCard.productRemark')" name="mark">
<t-textarea v-model="textareaValue" :style="{ width: '480px' }" placeholder="请输入内容" name="description" /> <t-textarea v-model="textareaValue" :style="{ width: '480px' }" name="description" />
</t-form-item> </t-form-item>
<t-form-item style="float: right"> <t-form-item style="float: right">
<t-button variant="outline" @click="onClickCloseBtn">取消</t-button> <t-button variant="outline" @click="onClickCloseBtn">取消</t-button>

View File

@ -1,9 +1,9 @@
<template> <template>
<div> <div>
<div class="list-card-operation"> <div class="list-card-operation">
<t-button @click="formDialogVisible = true"> 新建产品 </t-button> <t-button @click="formDialogVisible = true"> {{ $t('pages.listCard.create') }} </t-button>
<div class="search-input"> <div class="search-input">
<t-input v-model="searchValue" placeholder="请输入你需要搜索的内容" clearable> <t-input v-model="searchValue" :placeholder="$t('pages.listCard.placeholder')" clearable>
<template #suffix-icon> <template #suffix-icon>
<search-icon v-if="searchValue === ''" size="var(--td-comp-size-xxxs)" /> <search-icon v-if="searchValue === ''" size="var(--td-comp-size-xxxs)" />
</template> </template>

View File

@ -7,5 +7,5 @@ export default {
}; };
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
import CommonTable from '../components/CommonTable.vue'; import CommonTable from '@/components/common-table/index.vue';
</script> </script>

View File

@ -2,7 +2,7 @@
<div class="table-tree-container"> <div class="table-tree-container">
<div class="list-tree-wrapper"> <div class="list-tree-wrapper">
<div class="list-tree-operator"> <div class="list-tree-operator">
<t-input v-model="filterText" placeholder="请输入关键词" @change="onInput"> <t-input v-model="filterText" :placeholder="$t('pages.listTree.placeholder')" @change="onInput">
<template #suffix-icon> <template #suffix-icon>
<search-icon size="var(--td-comp-size-xxxs)" /> <search-icon size="var(--td-comp-size-xxxs)" />
</template> </template>
@ -27,7 +27,8 @@ import { SearchIcon } from 'tdesign-icons-vue-next';
import type { TreeNodeModel } from 'tdesign-vue-next'; import type { TreeNodeModel } from 'tdesign-vue-next';
import { ref } from 'vue'; import { ref } from 'vue';
import CommonTable from '../components/CommonTable.vue'; import CommonTable from '@/components/common-table/index.vue';
import { TREE_DATA } from './constants'; import { TREE_DATA } from './constants';
const filterByText = ref(); const filterByText = ref();

View File

@ -9,7 +9,7 @@
> >
<template v-if="type == 'password'"> <template v-if="type == 'password'">
<t-form-item name="account"> <t-form-item name="account">
<t-input v-model="formData.account" size="large" placeholder="请输入账号admin"> <t-input v-model="formData.account" size="large" :placeholder="`${$t('pages.login.input.account')}admin`">
<template #prefix-icon> <template #prefix-icon>
<t-icon name="user" /> <t-icon name="user" />
</template> </template>
@ -22,7 +22,7 @@
size="large" size="large"
:type="showPsw ? 'text' : 'password'" :type="showPsw ? 'text' : 'password'"
clearable clearable
placeholder="请输入登录密码admin" :placeholder="`${$t('pages.login.input.password')}admin`"
> >
<template #prefix-icon> <template #prefix-icon>
<t-icon name="lock-on" /> <t-icon name="lock-on" />
@ -34,16 +34,16 @@
</t-form-item> </t-form-item>
<div class="check-container remember-pwd"> <div class="check-container remember-pwd">
<t-checkbox>记住账号</t-checkbox> <t-checkbox>{{ $t('pages.login.remember') }}</t-checkbox>
<span class="tip">忘记账号</span> <span class="tip">{{ $t('pages.login.forget') }}</span>
</div> </div>
</template> </template>
<!-- 扫码登录 --> <!-- 扫码登录 -->
<template v-else-if="type == 'qrcode'"> <template v-else-if="type == 'qrcode'">
<div class="tip-container"> <div class="tip-container">
<span class="tip">请使用微信扫一扫登录</span> <span class="tip">{{ $t('pages.login.wechatLogin') }}</span>
<span class="refresh">刷新 <t-icon name="refresh" /> </span> <span class="refresh">{{ $t('pages.login.refresh') }} <t-icon name="refresh" /> </span>
</div> </div>
<qrcode-vue value="" :size="160" level="H" /> <qrcode-vue value="" :size="160" level="H" />
</template> </template>
@ -51,7 +51,7 @@
<!-- 手机号登录 --> <!-- 手机号登录 -->
<template v-else> <template v-else>
<t-form-item name="phone"> <t-form-item name="phone">
<t-input v-model="formData.phone" size="large" placeholder="请输入手机号码"> <t-input v-model="formData.phone" size="large" :placeholder="$t('pages.login.input.phone')">
<template #prefix-icon> <template #prefix-icon>
<t-icon name="mobile" /> <t-icon name="mobile" />
</template> </template>
@ -59,21 +59,25 @@
</t-form-item> </t-form-item>
<t-form-item class="verification-code" name="verifyCode"> <t-form-item class="verification-code" name="verifyCode">
<t-input v-model="formData.verifyCode" size="large" placeholder="请输入验证码" /> <t-input v-model="formData.verifyCode" size="large" :placeholder="$t('pages.login.input.verification')" />
<t-button size="large" variant="outline" :disabled="countDown > 0" @click="sendCode"> <t-button size="large" variant="outline" :disabled="countDown > 0" @click="sendCode">
{{ countDown == 0 ? '发送验证码' : `${countDown}秒后可重发` }} {{ countDown == 0 ? $t('pages.login.sendVerification') : `${countDown}秒后可重发` }}
</t-button> </t-button>
</t-form-item> </t-form-item>
</template> </template>
<t-form-item v-if="type !== 'qrcode'" class="btn-container"> <t-form-item v-if="type !== 'qrcode'" class="btn-container">
<t-button block size="large" type="submit"> 登录 </t-button> <t-button block size="large" type="submit"> {{ $t('pages.login.signIn') }} </t-button>
</t-form-item> </t-form-item>
<div class="switch-container"> <div class="switch-container">
<span v-if="type !== 'password'" class="tip" @click="switchType('password')">使用账号密码登录</span> <span v-if="type !== 'password'" class="tip" @click="switchType('password')">{{
<span v-if="type !== 'qrcode'" class="tip" @click="switchType('qrcode')">使用微信扫码登录</span> $t('pages.login.accountLogin')
<span v-if="type !== 'phone'" class="tip" @click="switchType('phone')">使用手机号登录</span> }}</span>
<span v-if="type !== 'qrcode'" class="tip" @click="switchType('qrcode')">{{
$t('pages.login.wechatLogin')
}}</span>
<span v-if="type !== 'phone'" class="tip" @click="switchType('phone')">{{ $t('pages.login.phoneLogin') }}</span>
</div> </div>
</t-form> </t-form>
</template> </template>
@ -86,6 +90,7 @@ import { ref } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { useCounter } from '@/hooks'; import { useCounter } from '@/hooks';
import { t } from '@/locales';
import { useUserStore } from '@/store'; import { useUserStore } from '@/store';
const userStore = useUserStore(); const userStore = useUserStore();
@ -99,10 +104,10 @@ const INITIAL_DATA = {
}; };
const FORM_RULES: Record<string, FormRule[]> = { const FORM_RULES: Record<string, FormRule[]> = {
phone: [{ required: true, message: '手机号必填', type: 'error' }], phone: [{ required: true, message: t('pages.login.required.phone'), type: 'error' }],
account: [{ required: true, message: '账号必填', type: 'error' }], account: [{ required: true, message: t('pages.login.required.account'), type: 'error' }],
password: [{ required: true, message: '密码必填', type: 'error' }], password: [{ required: true, message: t('pages.login.required.password'), type: 'error' }],
verifyCode: [{ required: true, message: '验证码必填', type: 'error' }], verifyCode: [{ required: true, message: t('pages.login.required.verification'), type: 'error' }],
}; };
const type = ref('password'); const type = ref('password');
@ -149,5 +154,5 @@ const onSubmit = async (ctx: SubmitContext) => {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import url('../index.less'); @import '../index.less';
</style> </style>

View File

@ -4,12 +4,12 @@
<div class="login-container"> <div class="login-container">
<div class="title-container"> <div class="title-container">
<h1 class="title margin-no">登录到</h1> <h1 class="title margin-no">{{ $t('pages.login.loginTitle') }}</h1>
<h1 class="title">TDesign Starter</h1> <h1 class="title">TDesign Starter</h1>
<div class="sub-title"> <div class="sub-title">
<p class="tip">{{ type == 'register' ? '已有账号?' : '没有账号吗?' }}</p> <p class="tip">{{ type == 'register' ? $t('pages.login.existAccount') : $t('pages.login.noAccount') }}</p>
<p class="tip" @click="switchType(type == 'register' ? 'login' : 'register')"> <p class="tip" @click="switchType(type == 'register' ? 'login' : 'register')">
{{ type == 'register' ? '登录' : '注册新账号' }} {{ type == 'register' ? $t('pages.login.signIn') : $t('pages.login.createAccount') }}
</p> </p>
</div> </div>
</div> </div>
@ -19,7 +19,7 @@
<tdesign-setting /> <tdesign-setting />
</div> </div>
<footer class="copyright">Copyright @ 2021-2022 Tencent. All Rights Reserved</footer> <footer class="copyright">Copyright @ 2021-2023 Tencent. All Rights Reserved</footer>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -43,5 +43,5 @@ const switchType = (val: string) => {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import url('./index.less'); @import './index.less';
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<result title="403 Forbidden" tip="抱歉您无权限访问此页面企业微信联系创建者xiaolaoshi"> <result title="403 Forbidden" :tip="$t('pages.result.403.tips')">
<t-button @click="() => $router.push('/')">返回首页</t-button> <t-button @click="() => $router.push('/')">{{ $t('pages.result.403.back') }}</t-button>
</result> </result>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -1,6 +1,6 @@
<template> <template>
<result title="404 Not Found" tip="抱歉,您访问的页面不存在" type="404"> <result title="404 Not Found" :tip="$t('pages.result.404.subtitle')" type="404">
<t-button @click="() => $router.push('/')">返回首页</t-button> <t-button @click="() => $router.push('/')">{{ $t('pages.result.404.back') }}</t-button>
</result> </result>
</template> </template>

View File

@ -1,6 +1,6 @@
<template> <template>
<result title="500 Internal Server Error" type="500" tip="抱歉,服务器出错啦"> <result title="500 Internal Server Error" type="500" :tip="$t('pages.result.500.subtitle')">
<t-button @click="() => $router.push('/')">返回首页</t-button> <t-button @click="() => $router.push('/')">{{ $t('pages.result.500.back') }}</t-button>
</result> </result>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -1,9 +1,15 @@
<template> <template>
<result title="浏览器不兼容" type="ie" tip="抱歉,您正在使用的浏览器版本过低,无法打开当前网页。"> <result
:title="$t('pages.result.browserIncompatible.title')"
type="ie"
:tip="$t('pages.result.browserIncompatible.subtitle')"
>
<div class="result-slot-container"> <div class="result-slot-container">
<t-button class="result-button" @click="() => $router.push('/')">返回首页</t-button> <t-button class="result-button" @click="() => $router.push('/')">{{
$t('pages.result.browserIncompatible.back')
}}</t-button>
<div class="recommend-container"> <div class="recommend-container">
<div>TDesign Starter 推荐以下主流浏览器</div> <div>{{ $t('pages.result.browserIncompatible.recommend') }}</div>
<div class="recommend-browser"> <div class="recommend-browser">
<div> <div>
<thumbnail class="browser-icon" url="https://tdesign.gtimg.com/starter/result-page/chorme.png" /> <thumbnail class="browser-icon" url="https://tdesign.gtimg.com/starter/result-page/chorme.png" />
@ -47,7 +53,7 @@ import Thumbnail from '@/components/thumbnail/index.vue';
padding: var(--td-comp-paddingTB-xl) var(--td-comp-paddingLR-xxl); padding: var(--td-comp-paddingTB-xl) var(--td-comp-paddingLR-xxl);
width: 640px; width: 640px;
background: var(--td-bg-color-container); background: var(--td-bg-color-container);
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 1px 2px rgb(0 0 0 / 10%);
border-radius: var(--td-radius-medium); border-radius: var(--td-radius-medium);
} }

View File

@ -1,11 +1,13 @@
<template> <template>
<div class="result-success"> <div class="result-success">
<t-icon class="result-success-icon" name="error-circle" /> <t-icon class="result-success-icon" name="error-circle" />
<div class="result-success-title">项目创建失败</div> <div class="result-success-title">{{ $t('pages.result.fail.title') }}</div>
<div class="result-success-describe">企业微信联系检查创建者权限或返回修改</div> <div class="result-success-describe">{{ $t('pages.result.fail.subtitle') }}</div>
<div> <div>
<t-button theme="default" @click="() => $router.push('/dashboard/base')">返回首页</t-button> <t-button theme="default" @click="() => $router.push('/dashboard/base')">{{
<t-button @click="() => $router.push('/form/base')">返回修改</t-button> $t('pages.result.fail.back')
}}</t-button>
<t-button @click="() => $router.push('/form/base')">{{ $t('pages.result.fail.modify') }} </t-button>
</div> </div>
</div> </div>
</template> </template>
@ -21,6 +23,7 @@ export default {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 75vh; height: 75vh;
&-icon { &-icon {
font-size: var(--td-comp-size-xxxxl); font-size: var(--td-comp-size-xxxxl);
color: var(--td-text-color-secondary); color: var(--td-text-color-secondary);

View File

@ -1,6 +1,10 @@
<template> <template>
<result title="系统维护中" tip="系统维护中,请稍后再试" type="maintenance"> <result
<t-button theme="primary" @click="() => $router.push('/')">返回首页</t-button> :title="$t('pages.result.maintenance.title')"
:tip="$t('pages.result.maintenance.subtitle')"
type="maintenance"
>
<t-button theme="primary" @click="() => $router.push('/')">{{ $t('pages.result.maintenance.back') }}</t-button>
</result> </result>
</template> </template>

View File

@ -1,8 +1,8 @@
<template> <template>
<result title="网络异常" tip="网络异常,请稍后再试" type="wifi"> <result :title="$t('pages.result.networkError.title')" :tip="$t('pages.result.networkError.subtitle')" type="wifi">
<div> <div>
<t-button theme="default" @click="() => $router.push('/')">返回首页</t-button> <t-button theme="default" @click="() => $router.push('/')">{{ $t('pages.result.networkError.back') }}</t-button>
<t-button @click="() => $router.push('/')">重新加载</t-button> <t-button @click="() => $router.push('/')">{{ $t('pages.result.networkError.reload') }}</t-button>
</div> </div>
</result> </result>
</template> </template>

View File

@ -1,11 +1,13 @@
<template> <template>
<div class="result-success"> <div class="result-success">
<t-icon class="result-success-icon" name="check-circle" /> <t-icon class="result-success-icon" name="check-circle" />
<div class="result-success-title">项目已创建成功</div> <div class="result-success-title">{{ $t('pages.result.success.title') }}</div>
<div class="result-success-describe">可以联系负责人分发应用</div> <div class="result-success-describe">{{ $t('pages.result.success.subtitle') }}</div>
<div> <div>
<t-button theme="default" @click="() => $router.push('/detail/advanced')"> 查看进度 </t-button> <t-button theme="default" @click="() => $router.push('/detail/advanced')">
<t-button @click="() => $router.push('/form/base')"> 返回首页 </t-button> {{ $t('pages.result.success.progress') }}
</t-button>
<t-button @click="() => $router.push('/dashboard/base')"> {{ $t('pages.result.success.back') }} </t-button>
</div> </div>
</div> </div>
</template> </template>

View File

@ -1,3 +1,5 @@
import { t } from '@/locales';
export interface UserInfoListType { export interface UserInfoListType {
title: string; title: string;
content: string; content: string;
@ -6,39 +8,39 @@ export interface UserInfoListType {
export const USER_INFO_LIST: Array<UserInfoListType> = [ export const USER_INFO_LIST: Array<UserInfoListType> = [
{ {
title: '手机', title: t('pages.user.personalInfo.desc.mobile'),
content: '+86 13923734567', content: '+86 13923734567',
}, },
{ {
title: '座机', title: t('pages.user.personalInfo.desc.phone'),
content: '734567', content: '734567',
}, },
{ {
title: '办公室邮箱', title: t('pages.user.personalInfo.desc.email'),
content: 'Account@qq.com', content: 'Account@qq.com',
}, },
{ {
title: '座位', title: t('pages.user.personalInfo.desc.seat'),
content: 'T32F 012', content: 'T32F 012',
}, },
{ {
title: '管理主体', title: t('pages.user.personalInfo.desc.entity'),
content: '腾讯集团', content: '腾讯集团',
}, },
{ {
title: '直属上级', title: t('pages.user.personalInfo.desc.leader'),
content: 'Michael Wang', content: 'Michael Wang',
}, },
{ {
title: '职位', title: t('pages.user.personalInfo.desc.position'),
content: '高级 UI 设计师', content: '高级 UI 设计师',
}, },
{ {
title: '入职时间', title: t('pages.user.personalInfo.desc.joinDay'),
content: '2021-07-01', content: '2021-07-01',
}, },
{ {
title: '所属团队', title: t('pages.user.personalInfo.desc.group'),
content: '腾讯/腾讯公司/某事业群/某产品部/某运营中心/商户服务组', content: '腾讯/腾讯公司/某事业群/某产品部/某运营中心/商户服务组',
span: 6, span: 6,
}, },

View File

@ -4,12 +4,12 @@
<div class="user-left-greeting"> <div class="user-left-greeting">
<div> <div>
HiImage HiImage
<span class="regular"> 下午好今天是你加入鹅厂的第 100 </span> <span class="regular"> {{ $t('pages.user.markDay') }}</span>
</div> </div>
<img src="@/assets/assets-tencent-logo.png" class="logo" /> <img src="@/assets/assets-tencent-logo.png" class="logo" />
</div> </div>
<t-card class="user-info-list" title="个人信息" :bordered="false"> <t-card class="user-info-list" :title="$t('pages.user.personalInfo.title')" :bordered="false">
<template #actions> <template #actions>
<t-button theme="default" shape="square" variant="text"> <t-button theme="default" shape="square" variant="text">
<t-icon name="ellipsis" /> <t-icon name="ellipsis" />
@ -29,11 +29,11 @@
<t-card class="content-container" :bordered="false"> <t-card class="content-container" :bordered="false">
<t-tabs value="second"> <t-tabs value="second">
<t-tab-panel value="first" label="内容列表"> <t-tab-panel value="first" :label="$t('pages.user.contentList')">
<p>内容列表</p> <p>{{ $t('pages.user.contentList') }}</p>
</t-tab-panel> </t-tab-panel>
<t-tab-panel value="second" label="内容列表"> <t-tab-panel value="second" :label="$t('pages.user.contentList')">
<t-card :bordered="false" class="card-padding-no" title="主页访问数据" describe="(次)"> <t-card :bordered="false" class="card-padding-no" :title="$t('pages.user.visitData')" describe="(次)">
<template #actions> <template #actions>
<t-date-range-picker <t-date-range-picker
class="card-date-picker-container" class="card-date-picker-container"
@ -46,8 +46,8 @@
<div id="lineContainer" style="width: 100%; height: 328px" /> <div id="lineContainer" style="width: 100%; height: 328px" />
</t-card> </t-card>
</t-tab-panel> </t-tab-panel>
<t-tab-panel value="third" label="内容列表"> <t-tab-panel value="third" :label="$t('pages.user.contentList')">
<p>内容列表</p> <p>{{ $t('pages.user.contentList') }}</p>
</t-tab-panel> </t-tab-panel>
</t-tabs> </t-tabs>
</t-card> </t-card>
@ -57,10 +57,10 @@
<t-card class="user-intro" :bordered="false"> <t-card class="user-intro" :bordered="false">
<t-avatar size="80px">T</t-avatar> <t-avatar size="80px">T</t-avatar>
<div class="name">My Account</div> <div class="name">My Account</div>
<div class="position">XXG 港澳业务拓展组员工 直客销售</div> <div class="position">{{ $t('pages.user.personalInfo.position') }}</div>
</t-card> </t-card>
<t-card title="团队成员" class="user-team" :bordered="false"> <t-card :title="$t('pages.user.teamMember')" class="user-team" :bordered="false">
<template #actions> <template #actions>
<t-button theme="default" shape="square" variant="text"> <t-button theme="default" shape="square" variant="text">
<t-icon name="ellipsis" /> <t-icon name="ellipsis" />
@ -73,7 +73,7 @@
</t-list> </t-list>
</t-card> </t-card>
<t-card title="服务产品" class="product-container" :bordered="false"> <t-card :title="$t('pages.user.serviceProduction')" class="product-container" :bordered="false">
<template #actions> <template #actions>
<t-button theme="default" shape="square" variant="text"> <t-button theme="default" shape="square" variant="text">
<t-icon name="ellipsis" /> <t-icon name="ellipsis" />
@ -184,5 +184,5 @@ watch(
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import url('./index.less'); @import './index.less';
</style> </style>

View File

@ -10,7 +10,10 @@ export default [
redirect: '/dashboard/base', redirect: '/dashboard/base',
name: 'dashboard', name: 'dashboard',
meta: { meta: {
title: '仪表盘', title: {
zh_CN: '仪表盘',
en_US: 'Dashboard',
},
icon: shallowRef(DashboardIcon), icon: shallowRef(DashboardIcon),
orderNo: 0, orderNo: 0,
}, },
@ -20,7 +23,10 @@ export default [
name: 'DashboardBase', name: 'DashboardBase',
component: () => import('@/pages/dashboard/base/index.vue'), component: () => import('@/pages/dashboard/base/index.vue'),
meta: { meta: {
title: '概览仪表盘', title: {
zh_CN: '概览仪表盘',
en_US: 'Overview',
},
}, },
}, },
{ {
@ -28,7 +34,10 @@ export default [
name: 'DashboardDetail', name: 'DashboardDetail',
component: () => import('@/pages/dashboard/detail/index.vue'), component: () => import('@/pages/dashboard/detail/index.vue'),
meta: { meta: {
title: '统计报表', title: {
zh_CN: '统计报表',
en_US: 'Dashboard Detail',
},
}, },
}, },
], ],

View File

@ -6,55 +6,76 @@ export default [
name: 'result', name: 'result',
component: Layout, component: Layout,
redirect: '/result/success', redirect: '/result/success',
meta: { title: '结果页', icon: 'check-circle' }, meta: {
title: {
zh_CN: '结果页',
en_US: 'Result',
},
icon: 'check-circle',
},
children: [ children: [
{ {
path: 'success', path: 'success',
name: 'ResultSuccess', name: 'ResultSuccess',
component: () => import('@/pages/result/success/index.vue'), component: () => import('@/pages/result/success/index.vue'),
meta: { title: '成功页' }, meta: {
title: {
zh_CN: '成功页',
en_US: 'Success',
},
},
}, },
{ {
path: 'fail', path: 'fail',
name: 'ResultFail', name: 'ResultFail',
component: () => import('@/pages/result/fail/index.vue'), component: () => import('@/pages/result/fail/index.vue'),
meta: { title: '失败页' }, meta: {
title: {
zh_CN: '失败页',
en_US: 'Fail',
},
},
}, },
{ {
path: 'network-error', path: 'network-error',
name: 'ResultNetworkError', name: 'ResultNetworkError',
component: () => import('@/pages/result/network-error/index.vue'), component: () => import('@/pages/result/network-error/index.vue'),
meta: { title: '网络异常' }, meta: {
title: {
zh_CN: '网络异常',
en_US: 'Network Error',
},
},
}, },
{ {
path: '403', path: '403',
name: 'Result403', name: 'Result403',
component: () => import('@/pages/result/403/index.vue'), component: () => import('@/pages/result/403/index.vue'),
meta: { title: '无权限' }, meta: { title: { zh_CN: '无权限', en_US: 'Forbidden' } },
}, },
{ {
path: '404', path: '404',
name: 'Result404', name: 'Result404',
component: () => import('@/pages/result/404/index.vue'), component: () => import('@/pages/result/404/index.vue'),
meta: { title: '访问页面不存在页' }, meta: { title: { zh_CN: '访问页面不存在页', en_US: 'Not Found' } },
}, },
{ {
path: '500', path: '500',
name: 'Result500', name: 'Result500',
component: () => import('@/pages/result/500/index.vue'), component: () => import('@/pages/result/500/index.vue'),
meta: { title: '服务器出错页' }, meta: { title: { zh_CN: '服务器出错页', en_US: 'Server Error' } },
}, },
{ {
path: 'browser-incompatible', path: 'browser-incompatible',
name: 'ResultBrowserIncompatible', name: 'ResultBrowserIncompatible',
component: () => import('@/pages/result/browser-incompatible/index.vue'), component: () => import('@/pages/result/browser-incompatible/index.vue'),
meta: { title: '浏览器不兼容页' }, meta: { title: { zh_CN: '浏览器不兼容页', en_US: 'BrowserIncompatible' } },
}, },
{ {
path: 'maintenance', path: 'maintenance',
name: 'ResultMaintenance', name: 'ResultMaintenance',
component: () => import('@/pages/result/maintenance/index.vue'), component: () => import('@/pages/result/maintenance/index.vue'),
meta: { title: '系统维护页' }, meta: { title: { zh_CN: '系统维护页', en_US: 'Maintenance' } },
}, },
], ],
}, },

View File

@ -9,13 +9,13 @@ export default [
name: 'user', name: 'user',
component: Layout, component: Layout,
redirect: '/user/index', redirect: '/user/index',
meta: { title: '个人页', icon: 'user-circle' }, meta: { title: { zh_CN: '个人中心', en_US: 'User Center' }, icon: 'user-circle' },
children: [ children: [
{ {
path: 'index', path: 'index',
name: 'UserIndex', name: 'UserIndex',
component: () => import('@/pages/user/index.vue'), component: () => import('@/pages/user/index.vue'),
meta: { title: '个人中心' }, meta: { title: { zh_CN: '个人中心', en_US: 'User Center' } },
}, },
], ],
}, },
@ -23,14 +23,14 @@ export default [
path: '/loginRedirect', path: '/loginRedirect',
name: 'loginRedirect', name: 'loginRedirect',
redirect: '/login', redirect: '/login',
meta: { title: '登录页', icon: shallowRef(LogoutIcon) }, meta: { title: { zh_CN: '登录页', en_US: 'Login' }, icon: shallowRef(LogoutIcon) },
component: () => import('@/layouts/blank.vue'), component: () => import('@/layouts/blank.vue'),
children: [ children: [
{ {
path: 'index', path: 'index',
redirect: '/login', redirect: '/login',
component: () => import('@/layouts/blank.vue'), component: () => import('@/layouts/blank.vue'),
meta: { title: '登录中心' }, meta: { title: { zh_CN: '登录页', en_US: 'Login' } },
}, },
], ],
}, },