Commit 20fd7baf authored by hucy's avatar hucy

feat:i18n 学习

feat:文件上传组件封装
parent fe24dabc
## 2022-11-21
- i18n 学习
- 文件上传组件封装
## 2022-11-14 ## 2022-11-14
- canvas 绘制动态路径箭头 - canvas 绘制动态路径箭头
......
This diff is collapsed.
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
"pinia": "^2.0.14", "pinia": "^2.0.14",
"quasar": "^2.6.0", "quasar": "^2.6.0",
"vue": "^3.0.0", "vue": "^3.0.0",
"vue-router": "^4.0.0" "vue-i18n": "^9.2.2",
"vue-router": "^4.0.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.0/xlsx-0.19.0.tgz"
}, },
"devDependencies": { "devDependencies": {
"@quasar/app-webpack": "^3.0.0", "@quasar/app-webpack": "^3.0.0",
......
...@@ -30,7 +30,7 @@ module.exports = configure(function (ctx) { ...@@ -30,7 +30,7 @@ module.exports = configure(function (ctx) {
// app boot file (/src/boot) // app boot file (/src/boot)
// --> boot files are part of "main.js" // --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli-webpack/boot-files // https://v2.quasar.dev/quasar-cli-webpack/boot-files
boot: ['store'], boot: ['store', 'vue-i18n'],
// https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-css // https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-css
css: ['app.scss'], css: ['app.scss'],
......
import { boot } from 'quasar/wrappers';
import { createI18n } from 'vue-i18n';
import messages from 'src/i18n';
export default boot(({ app }) => {
// Create I18n instance
const i18n = createI18n({
// something vue-i18n options here ...
legacy: false, // you must set `false`, to use Composition API
locale: 'zh-CN', // set current locale
messages,
});
// Tell app to use the I18n instance
app.use(i18n);
});
/**
* Define the common constant
* 定义公共常数
*/
/**
* The prefix of web storage value, to ideintify the value data type.
* e.g __hcytest_object|{"key": "value"}
*/
// export const STORAGE_VALUE_PREFIX = '__hcytest_';
/**
* The key which save user last selected `Language` or `Local` to
* `SessionStorage` or `LocalStorage`
*/
export const LANG_STORAGE_KEY = 'LANG';
...@@ -4,6 +4,7 @@ const creatNotify = function (type: string, msg: string) { ...@@ -4,6 +4,7 @@ const creatNotify = function (type: string, msg: string) {
Notify.create({ Notify.create({
type, type,
message: msg, message: msg,
position: 'top',
}); });
}; };
type IMessage = { type IMessage = {
......
...@@ -5,6 +5,7 @@ import MyTooltip from './MyTooltip.vue'; ...@@ -5,6 +5,7 @@ import MyTooltip from './MyTooltip.vue';
import CanvasStaticRoute from './canvas-static-route/CanvasStaticRoute.vue'; import CanvasStaticRoute from './canvas-static-route/CanvasStaticRoute.vue';
import ChartCarouselWarp from './chart-carousel-warp/ChartCarouselWarp.vue'; import ChartCarouselWarp from './chart-carousel-warp/ChartCarouselWarp.vue';
import TitlePage from './title-page/TitlePage.vue'; import TitlePage from './title-page/TitlePage.vue';
import UpLoader from './uploader-page/UpLoader.vue';
export { export {
DateTimePick as ComDateTimePick, DateTimePick as ComDateTimePick,
...@@ -14,6 +15,7 @@ export { ...@@ -14,6 +15,7 @@ export {
CanvasStaticRoute as ComCanvasStaticRoute, CanvasStaticRoute as ComCanvasStaticRoute,
ChartCarouselWarp as ComChartCarouselWarp, ChartCarouselWarp as ComChartCarouselWarp,
TitlePage as ComTitlePage, TitlePage as ComTitlePage,
UpLoader as ComUpLoader,
}; };
export default { export default {
...@@ -24,4 +26,5 @@ export default { ...@@ -24,4 +26,5 @@ export default {
CanvasStaticRoute, CanvasStaticRoute,
ChartCarouselWarp, ChartCarouselWarp,
TitlePage, TitlePage,
UpLoader,
}; };
<!--
* 上传器
-->
<script setup lang="ts">
import { ref, reactive, computed, nextTick } from 'vue';
import { useMessage } from 'src/common/hooks';
import { getObjectURL } from './utils';
var XLSX = require('xlsx');
const { warn } = useMessage();
interface IDetailProps {
bgColor?: string; // 背景色
multiple?: boolean; // 多选
accept?: string; // 上传类型 'image/*'
dark?: boolean; // 启用深色背景
noShadow?: boolean; // 阴影
}
const props = withDefaults(defineProps<IDetailProps>(), {
bgColor: '#96C0CE',
multiple: false,
accept: '',
dark: false,
noShadow: false,
});
const emit = defineEmits<{
(e: 'onOk', value: any): void;
}>();
const darkDeep = '#222831';
const darkLight = '#393E46';
const imageTypeList = ['png', 'jpg', 'gif'];
const excelTypeList = ['xlsx', 'xls'];
const otherTypeList = ['pdf'];
const viewModel = ref(false);
const fileType = ref('');
const viewDialogTitle = ref('');
const state = reactive({
fileList: [] as any[],
viewTableHtml: null as any,
});
const canPreview = computed(() => (type: any) => {
const viewTypeList = imageTypeList.concat(excelTypeList, otherTypeList);
return viewTypeList.includes(type);
});
const totalSize = computed(() => {
const total = state.fileList.reduce((a, b) => a + b.size, 0);
let unit: string; // 单位
let size: number | string = 0;
if (total < 1000) {
unit = 'B';
size = total.toFixed(3);
} else {
const KB_size = total * 0.0009765625;
if (KB_size < 1000) {
unit = 'KB';
size = KB_size.toFixed(3);
} else {
const MB_size = KB_size * 0.0009765625;
if (MB_size < 1000) {
unit = 'MB';
size = MB_size.toFixed(2);
} else {
const GB_size = MB_size * 0.0009765625;
unit = 'GB';
size = GB_size.toFixed(2);
}
}
}
return size + unit;
});
function selectFile() {
let _input: HTMLInputElement = document.createElement('input'); // 创建一个隐藏的input
_input.setAttribute('type', 'file');
if (props.multiple) {
_input.setAttribute('multiple', true); // 多选
}
// _input.setAttribute('accept', 'image/*'); // 上传类型
if (props.accept) {
_input.setAttribute('accept', props.accept);
}
_input.onchange = function (e: any) {
let arr = [] as any[];
for (let i = 0; i < e.target.files.length; i++) {
const _file = e.target.files[i];
const typeArr = _file.name.split('.');
const type = typeArr.length > 1 ? typeArr[typeArr.length - 1] : '';
let unit: string; // 单位
let size: number | string = 0;
if (_file.size < 1000) {
unit = 'B';
size = _file.size.toFixed(3);
} else {
const KB_size = _file.size * 0.0009765625;
if (KB_size < 1000) {
unit = 'KB';
size = KB_size.toFixed(3);
} else {
const MB_size = KB_size * 0.0009765625;
if (MB_size < 1000) {
unit = 'MB';
size = MB_size.toFixed(2);
} else {
const GB_size = MB_size * 0.0009765625;
if (GB_size <= 2) {
unit = 'GB';
size = GB_size.toFixed(2);
} else {
const msg = '文件过大,请选择不超过2GB的文件';
warn(msg);
console.warn(msg);
return;
}
}
}
}
arr.push({
file: _file,
name: _file.name,
sizeFormat: size + unit,
fileType: type,
size: _file.size,
});
}
nextTick(() => {
state.fileList = state.fileList.concat(arr);
});
};
_input.click();
}
function removeItem(index: number) {
state.fileList.splice(index, 1);
}
function removeAll() {
state.fileList = [];
}
// 预览
function onView(data: any) {
if (excelTypeList.includes(data.fileType)) {
fileType.value = data.fileType;
viewDialogTitle.value = data.name;
viewModel.value = true;
void viewXlsx(data);
} else {
const url = getObjectURL(data.file);
window.open(url);
window.URL.revokeObjectURL(url);
}
}
async function viewXlsx(data: any) {
const file = data.file;
const _data = await file.arrayBuffer();
const wb = XLSX.read(_data);
const ws = wb.Sheets[wb.SheetNames[0]];
const ele = XLSX.utils.sheet_to_html(ws, { id: 'tabeller' });
state.viewTableHtml = ele;
}
function closeViewDialog() {
viewModel.value = false;
fileType.value = '';
state.viewTableHtml = null;
}
</script>
<template>
<div
class="com-uploader"
:class="{ 'shadow-4': !props.noShadow }"
:style="{
borderColor: props.dark ? darkDeep : props.bgColor,
backgroundColor: props.dark ? darkLight : '#ffffff',
}"
>
<div
class="uploader-title"
:style="{ backgroundColor: props.dark ? darkDeep : props.bgColor }"
>
<div class="icon">
<q-btn
v-if="state.fileList.length > 0"
style="width: 28px"
class="q-mr-xs"
dense
size="12px"
label="OK"
title="确认上传"
:style="{
backgroundColor: props.dark ? props.bgColor : '#fff',
color: props.dark ? darkLight : props.bgColor,
}"
@click="emit('onOk', state.fileList)"
/>
<q-btn
v-if="state.fileList.length > 0"
dense
flat
icon="bi-trash"
size="12px"
title="清除所有"
:style="{ color: props.dark ? props.bgColor : '#fff' }"
@click="removeAll"
/>
<span
v-if="state.fileList.length > 0"
:style="{
color: props.dark ? props.bgColor : '#fff',
}"
class="total-file-size"
>{{ totalSize }}</span
>
</div>
<div class="btn">
<q-btn
square
dense
push
icon="add"
size="12px"
title="选择文件"
label="选择文件"
:style="{
backgroundColor: props.dark ? props.bgColor : '#fff',
color: props.dark ? darkLight : props.bgColor,
}"
@click="selectFile"
/>
</div>
</div>
<div class="uploader-content">
<div class="uploader-main-content">
<div
class="file-item"
:style="{ borderColor: props.bgColor }"
v-for="(item, index) in state.fileList"
:key="index"
>
<div
class="name"
:title="item.name + ' ' + item.sizeFormat"
:style="{ color: props.bgColor }"
>
<span class="file-name">{{ item.name }}</span>
<span class="file-size">&nbsp;&nbsp;{{ item.sizeFormat }}</span>
</div>
<div class="btns">
<div>
<q-btn
v-if="canPreview(item.fileType)"
flat
dense
size="12px"
title="预览"
icon="bi-eye"
:style="{ color: props.bgColor }"
@click="onView(item)"
/>
</div>
<div>
<q-btn
flat
dense
size="12px"
title="从列表移除"
icon="bi-x-circle"
:style="{ color: props.bgColor }"
@click="removeItem(index)"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<q-dialog v-model="viewModel" persistent>
<q-card
style="min-height: 600px; min-width: 600px; max-width: 1400px"
class="column no-wrap"
>
<q-card-section class="row items-center q-pb-none">
<div class="text-h6">{{ viewDialogTitle }}</div>
<q-space />
<q-btn icon="close" flat round dense @click="closeViewDialog" />
</q-card-section>
<q-card-section class="q-pt-none overflow-auto" style="flex: 1">
<div v-if="excelTypeList.includes(fileType)">
<div v-html="state.viewTableHtml" class="table-view"></div>
</div>
</q-card-section>
</q-card>
</q-dialog>
</template>
<style lang="scss" scoped>
// 上传器
.com-uploader {
width: 100%;
min-width: 400px;
height: 100%;
min-height: 200px;
border-radius: 4px;
box-sizing: border-box;
border: 1px solid;
display: flex;
flex-flow: column nowrap;
// box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -2px,
// rgba(0, 0, 0, 0.3) 0px 3px 7px -3px;
.total-file-size {
display: inline-block;
font-size: 12px;
}
.uploader-title {
height: 46px;
padding: 8px;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
}
.uploader-content {
flex: 1;
overflow: auto;
}
.uploader-main-content {
display: grid;
grid-template-columns: 100%;
row-gap: 4px;
margin: 4px;
.file-item {
height: 40px;
box-sizing: border-box;
border-bottom: 2px solid;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
.name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.file-name {
font-weight: bold;
}
.file-size {
font-size: 12px;
}
}
.btns {
display: grid;
grid-template-columns: repeat(2, 1fr);
column-gap: 2px;
> div {
width: 28px;
}
}
}
}
// .dialog-box {
// // min-width: 600px;
// min-height: 600px;
// }
}
</style>
// 获取本地临时预览地址
export const getObjectURL = function (file: any) {
let url = null as any;
const _window = window as any;
if (_window.createObjectURL != undefined) {
url = _window.createObjectURL(file);
} else if (_window.URL != undefined) {
url = _window.URL.createObjectURL(file);
} else if (_window.webkitURL != undefined) {
url = _window.webkitURL.createObjectURL(file);
}
return url;
};
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
const development = { const development = {
name: 'TopPMS', name: 'TopPMS',
productName: 'TopPMS', productName: 'TopPMS',
storagePrefix: '__ABC__', storagePrefix: '__hcytest_',
langs: ['en-US', 'zh-CN', 'zh-TW'], langs: ['en-US', 'zh-CN', 'zh-TW'],
serverUrl: { base: 'http://139.196.104.13:9000' }, serverUrl: { base: 'http://139.196.104.13:9000' },
//http://192.168.2.100:29010 //http://192.168.2.100:29010
...@@ -12,7 +12,7 @@ const development = { ...@@ -12,7 +12,7 @@ const development = {
const production = { const production = {
name: 'TopPMS', name: 'TopPMS',
productName: 'TopPMS', productName: 'TopPMS',
storagePrefix: '__ABC__', storagePrefix: '__hcytest_',
langs: ['en-US', 'zh-CN', 'zh-TW'], langs: ['en-US', 'zh-CN', 'zh-TW'],
// serverUrl: { base: '' }, // serverUrl: { base: '' },
base_url: '', base_url: '',
......
export const Langs = [
{ label: '简体中文', value: 'zh-CN' },
{ label: '繁體中文', value: 'zh-TW' },
{ label: 'English', value: 'en-US' },
{ label: '日本', value: 'ja' },
];
...@@ -10,4 +10,6 @@ export default { ...@@ -10,4 +10,6 @@ export default {
refresh: 'bi-arrow-repeat', // 刷新 refresh: 'bi-arrow-repeat', // 刷新
delete: 'bi-trash', // 删除 delete: 'bi-trash', // 删除
alarm_clock: 'bi-stopwatch', // 闹钟 alarm_clock: 'bi-stopwatch', // 闹钟
export: 'fa-solid fa-file-export', // 导出
upload: 'fa-solid fa-cloud-arrow-up', // 上传
}; };
...@@ -50,3 +50,29 @@ a:hover { ...@@ -50,3 +50,29 @@ a:hover {
background-color: white; background-color: white;
box-shadow: rgba(0, 0, 0, 0.15) 0px 5px 15px 0px; box-shadow: rgba(0, 0, 0, 0.15) 0px 5px 15px 0px;
} }
.table-view {
position: relative;
table {
position: relative;
margin: 0 auto;
text-align: center;
background-color: #fafafa;
border: 1px solid #dadada;
border-collapse: collapse; /*表格的边框合并,如果相邻,则共用一个边框*/
border-spacing: 0; /*设置行与单元格边框的间距。当表格边框独立(即border-collapse:separate;)此属性才起作用*/
td {
padding: 4px;
border: 1px solid #dadada;
height: 30px;
min-height: 30px;
min-width: 100px;
}
th {
padding: 4px;
border: 1px solid #dadada;
height: 30px;
min-height: 30px;
}
}
}
...@@ -25,10 +25,10 @@ $accent: #9c27b0; ...@@ -25,10 +25,10 @@ $accent: #9c27b0;
$dark: #1d1d1d; $dark: #1d1d1d;
$positive: #8bc24c; $positive: #5bb318;
$negative: #e8222d; $negative: #d2001a;
$info: #90c078; $info: #ff8787;
$warning: #f7b32d; $warning: #ffb200;
$--color-white: #fff; $--color-white: #fff;
$--color-dark: #000; $--color-dark: #000;
...@@ -54,3 +54,5 @@ $border-color: rgba(0, 0, 0, 0.12); ...@@ -54,3 +54,5 @@ $border-color: rgba(0, 0, 0, 0.12);
$gray-text: #000000de; $gray-text: #000000de;
$gray-light-text: #00000098; $gray-light-text: #00000098;
$header-heigyht: 50px;
export default {
hello: 'hello!',
'World Cup': 'World Cup',
};
import zhCN from './zh-CN';
import zhTW from './zh-TW';
import enUS from './en-US';
import ja from './ja';
export default {
'zh-CN': zhCN,
'zh-TW': zhTW,
'en-US': enUS,
ja: ja,
};
export default {
hello: 'こんにちは!',
'World Cup': 'ワールドカップ',
};
export default {
hello: '你好!',
'World Cup': '世界杯',
};
export default {
hello: '你好!',
'World Cup': '世界盃',
};
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
</q-tabs> </q-tabs>
<q-space /> <q-space />
<language-select />
<div>Quasar v{{ $q.version }}</div> <div>Quasar v{{ $q.version }}</div>
</q-toolbar> </q-toolbar>
</q-header> </q-header>
...@@ -75,6 +76,7 @@ import { onBeforeRouteUpdate, useRouter } from 'vue-router'; ...@@ -75,6 +76,7 @@ import { onBeforeRouteUpdate, useRouter } from 'vue-router';
import { usePageStore } from 'src/common/hooks'; import { usePageStore } from 'src/common/hooks';
import EssentialLink from 'components/EssentialLink.vue'; import EssentialLink from 'components/EssentialLink.vue';
import TopLeftLoading from './TopLeftLoading.vue'; import TopLeftLoading from './TopLeftLoading.vue';
import LanguageSelect from './element/LanguageSelect.vue';
export default defineComponent({ export default defineComponent({
name: 'MainLayout', name: 'MainLayout',
...@@ -82,6 +84,7 @@ export default defineComponent({ ...@@ -82,6 +84,7 @@ export default defineComponent({
components: { components: {
EssentialLink, EssentialLink,
TopLeftLoading, TopLeftLoading,
LanguageSelect,
}, },
setup() { setup() {
...@@ -154,6 +157,13 @@ export default defineComponent({ ...@@ -154,6 +157,13 @@ export default defineComponent({
link: '/page6', link: '/page6',
active: false, active: false,
}, },
{
title: '七',
caption: '疫情防控',
icon: require('./menuListIcons/page7.svg'),
link: '/page7',
active: false,
},
]; ];
for (const item of lists) { for (const item of lists) {
......
<!--
* 语言选择
-->
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useLocalStorage } from 'src/common/hooks';
import { Langs } from 'src/config/enum';
// interface IDetailProps {
// type: string;
// data: any;
// }
// const props = withDefaults(defineProps<IDetailProps>(), {
// type: '',
// data: {},
// });
const { locale } = useI18n();
const { getItem, setItem } = useLocalStorage();
const languageLabel = ref('');
onMounted(() => {
let language = getItem('LANG');
let languageOpt = { label: '简体中文', value: 'zh-CN' };
if (language) {
languageOpt = JSON.parse(language as string);
} else {
setItem('LANG', JSON.stringify(languageOpt));
}
locale.value = languageOpt.value;
languageLabel.value = languageOpt.label;
});
function onItemClick(item: any) {
if (item.value === locale.value) return;
setItem('LANG', JSON.stringify(item));
languageLabel.value = item.label;
locale.value = item.value;
}
</script>
<template>
<div class="language-select">
<q-btn-dropdown :label="languageLabel" flat color="#fff" no-caps>
<q-list>
<q-item
clickable
v-close-popup
@click="onItemClick(item)"
v-for="item in Langs"
:key="item.value"
:class="{ 'active-sel-item': item.value === $i18n.locale }"
>
<q-item-section>
<q-item-label>{{ item.label }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</div>
</template>
<style lang="scss" scoped>
.language-select {
box-sizing: border-box;
height: $header-heigyht;
line-height: $header-heigyht;
margin-right: $padding-sm;
}
.active-sel-item {
color: $primary;
}
</style>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1668562510647" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15056" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M874.688 362.688H592.376v298.624h282.312c82.438 0 149.312-66.812 149.312-149.282 0-82.498-66.876-149.342-149.312-149.342z m0 256H635.062V405.344h239.624c58.812 0 106.624 47.876 106.624 106.688 0.002 58.78-47.81 106.656-106.622 106.656zM0 512.032c0 82.468 66.844 149.282 149.344 149.282h282.282V362.688H149.344C66.844 362.688 0 429.562 0 512.032z m388.968 106.656H149.344c-58.812 0-106.688-47.876-106.688-106.656 0-58.812 47.876-106.688 106.688-106.688h239.624v213.344z" fill="#CCD1D9" p-id="15057"></path><path d="M832 682.688c0 23.562-19.124 42.624-42.688 42.624H234.656c-23.562 0-42.656-19.062-42.656-42.624V341.344c0-23.562 19.094-42.656 42.656-42.656h554.656c23.562 0 42.688 19.094 42.688 42.656v341.344z" fill="#48CFAD" p-id="15058"></path><path d="M789.312 298.688h-42.624c23.562 0 42.624 19.094 42.624 42.656v341.344c0 23.562-19.062 42.624-42.624 42.624h42.624c23.562 0 42.688-19.062 42.688-42.624V341.344c0-23.562-19.124-42.656-42.688-42.656z" fill="#FFFFFF" opacity=".2" p-id="15059"></path><path d="M725.718 597.312H299.032v0.062c-0.124 0-0.25-0.062-0.376-0.062-11.75 0-21.312 9.562-21.312 21.376 0 11.75 9.562 21.312 21.312 21.312H725.72c11.782 0 21.344-9.562 21.344-21.312-0.002-11.812-9.564-21.376-21.346-21.376zM298.468 554.688c0.124 0 0.25-0.062 0.376-0.062v0.062h426.688c11.782 0 21.344-9.562 21.344-21.344s-9.562-21.312-21.344-21.312H298.468c-11.782 0-21.312 9.532-21.312 21.312s9.532 21.344 21.312 21.344z" fill="#37BC9B" p-id="15060"></path></svg>
\ No newline at end of file
...@@ -19,7 +19,8 @@ export default { ...@@ -19,7 +19,8 @@ export default {
// import SubComponents from './element/RequestAnimationFrame.vue'; // import SubComponents from './element/RequestAnimationFrame.vue';
// import SubComponents from './element/equipment/IndexPage.vue'; // import SubComponents from './element/equipment/IndexPage.vue';
import SubComponents from './element/canvas-router-map/CanvasRouterMap.vue'; // canvas 绘制动态路径 // import SubComponents from './element/canvas-router-map/CanvasRouterMap.vue'; // canvas 绘制动态路径
import SubComponents from './element/table-study/TableStudy.vue'; // 表格学习
</script> </script>
<template> <template>
<div class="page6 container-height"> <div class="page6 container-height">
......
This diff is collapsed.
<!--
* 疫情防控
-->
<script lang="ts">
export default {
name: 'PAGE7',
};
</script>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
type EChartsOption = echarts.EChartsOption;
var chartMain;
const chartMainRef = ref<any>(null);
onMounted(() => {
initDom();
});
function initDom() {
chartMain = echarts.init(chartMainRef.value);
const option: EChartsOption = {
tooltip: {
trigger: 'axis',
},
legend: {
data: [
'本土感染者',
'省内感染者',
'外省来(返)蓉感染者',
'境外输入感染者',
],
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: 40,
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [
'2022-11-08',
'2022-11-09',
'2022-11-10',
'2022-11-11',
'2022-11-12',
'2022-11-13',
'2022-11-14',
'2022-11-15',
'2022-11-16',
'2022-11-17',
'2022-11-18',
'2022-11-19',
'2022-11-20',
],
},
yAxis: {
type: 'value',
},
series: [
{
name: '本土感染者',
type: 'line',
data: [30, 35, 50, 48, 57, 99, 133, 100, 121, 176, 211, 200, 316],
itemStyle: {
color: '#E8110F',
},
},
{
name: '省内感染者',
type: 'line',
data: [16, 22, 28, 29, 40, 79, 115, 82, 107, 157, 192, 184, 280],
itemStyle: {
color: '#FBC723',
},
},
{
name: '外省来(返)蓉感染者',
type: 'line',
data: [14, 13, 22, 19, 17, 20, 18, 18, 14, 19, 19, 16, 36],
itemStyle: {
color: '#1B6AA5',
},
},
{
name: '境外输入感染者',
type: 'line',
data: [7, 15, 26, 10, 5, 9, 9, 8, 21, 17, 17, 12, 20],
itemStyle: {
color: '#333333',
},
},
],
};
chartMain.setOption(option);
}
</script>
<template>
<div>
<div>成都市新冠疫情单日新增情况</div>
<div class="content">
<div
class="chart-main"
ref="chartMainRef"
style="width: 1200px; height: 700px"
></div>
</div>
</div>
</template>
<style lang="scss" scoped>
.content {
display: flex;
justify-content: center;
}
.chart-main {
}
</style>
...@@ -67,7 +67,17 @@ const routes: RouteRecordRaw[] = [ ...@@ -67,7 +67,17 @@ const routes: RouteRecordRaw[] = [
name: 'PAGE6', name: 'PAGE6',
component: () => import('../modules/page6/IndexPage.vue'), component: () => import('../modules/page6/IndexPage.vue'),
meta: { meta: {
title: '页面6', title: '一些js练习',
permission: ['*'],
keepalive: true,
},
},
{
path: 'page7',
name: 'PAGE7',
component: () => import('../modules/page7/IndexPage.vue'),
meta: {
title: '页面7',
permission: ['*'], permission: ['*'],
keepalive: true, keepalive: true,
}, },
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment