提交 b2845271 authored 作者: 王鹏飞's avatar 王鹏飞

init

上级
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-typescript/recommended'],
env: {
'vue/setup-compiler-macros': true
},
rules: {
'vue/multi-word-component-names': 'off'
}
}
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
{
"recommendations": ["johnsoncodehk.volar", "johnsoncodehk.vscode-typescript-vue-plugin"]
}
# saas
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```
import fs from 'fs'
import path from 'path'
import chalk from 'chalk'
import OSS from 'ali-oss'
const log = console.log
const client = new OSS({
region: 'oss-cn-beijing',
accessKeyId: 'LTAIOTuuLTaWoGJj',
accessKeySecret: 'dE5tTGm2lh35eItct2krW2DeH2lf2I',
bucket: 'webapp-pub'
})
async function uploadTarget(src, dist) {
try {
const result = await client.put(dist, path.join(__dirname, src))
log(chalk.green('上传成功', result.url))
} catch (e) {
log(chalk.red('上传失败', src))
log(e)
}
}
function generateUploadTarget(src, dist) {
fs.readdir(path.join(__dirname, src), function (err, files) {
if (err) {
log(err)
return
}
files.forEach(function (file) {
const _src = src + '/' + file
const _dist = dist + '/' + file
const stats = fs.statSync(path.join(__dirname, _src))
// 判断是否为文件
stats.isFile() && uploadTarget(_src, _dist)
// 判断是否为文件夹
stats.isDirectory() && generateUploadTarget(_src, _dist)
})
})
}
generateUploadTarget('./dist', '/website/prod/saas')
/// <reference types="vite/client" />
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAn0EINdIXTDCzmR7J5FOjOV+PbXt7GNO6fanoCGe2O0CPRlNf
2Ea/wv6SlRtJPd0ohmnKqZdUbBpAsiV4ggOdOqeEB6utVYQWY/zhXRKYeRjN/iDu
WCRY5S+eRVkSzVOJP9DlBn6dnHSsWj55h1PrkIac8B862F/cVno/Wk5dqU55ZUoN
wHGw5Goz3R37w+Q0C9HRS5mrmPqI+Ogy8TJrIRxw9YAj5OlvuqBAeYAW1sNdEfsi
mMB0H2fbbXqEL4AsipE5ppP7Ij3vxVpxvmnl/SO7N6+Fit6r25VeFSvplK+PIV3c
UsK3PCKV2sOo0BDWtWFQh5hW3fK5RYjLpNDHCwIDAQABAoIBAEkiBDMzF5/VfaSD
jxNblUlzqNoOKqlsEehDblrtxbHQI/uXrhwT4VwarBXtQeU2+rU/P+JBrHM4Wx10
N7L9FecppmgfXqo2zlF8f8HOGFcEHRTm6o1vo6McCwKttQS1qAG2XHZvDtIagkuv
BQAwea0VJFzg+pUC8JyF5zIBauGkfk8eHTLFVuIEJoSJbPWBYzp7Vf1SCjXqs3YY
aZ5QkOqY7S81D2EULFAWiMIMdY/PVT5DSXxsjaJFkvxjDedA4jNCplyODBKdpnBb
kfoJTJ7qsSnqgJ2y2xRdRlvZalE49lr2MkW254s5GH35+hMYam0bffgLXdPz6RIs
7X0atYECgYEA1A9G+0+uYlyxddyR54QlWGK7L3wP+REMXultudT9rq4S6qkHoOgP
rhi2kvZOqA0sMR7XMVz5nw0ouUMUVfW0YzudgAK99tdIuk6dP6VqVo9T4kqa0rXi
3ZKD51qGXbF22SndEWV68QEPzMCbf0E+kXl5MGGNnFtjZ5nxTGS+uH8CgYEAwECs
0T36EnLOCXZoi3rTeHr2pSO20VuFSgljnHA6Ups9Chu6h/iZ8t0XVNb8J14q7lFi
NY6b4D3FR/vwO3nFt7dvFYNFaFGuFrkAaH002p8EYWSckhlGcucBuKivBVUbhXuM
HMGmqGhAnnGCvCj/v4n5/wv3wtFYfzYWnYPHC3UCgYBZgbFGNhW28sT8qIL1I3PX
4KR9oHHlgOqlzQVBYMNKzbKyVXIg2pJzu36kfU4p5JV4jjnqXgIGvjkoKUYWGkVv
dSQ/eejQnYHXEYOR77H4ozqW00KSGa+OMl92cWExfsxZUTA8PYcs3nPayplXlyRf
ptQeNa7eBjzo57NPuV4+5QKBgQCrJihzUlBYshmYNPBXE25FOHpwgz3SXT5orbke
4I4bUhXh9NN3DqrGmWqW3Zi2108ywALFGQLNe1AwiCnSWNLafZOHvEhC2Uw48FNb
sfMmmR/GMFJugc/EpMBUit7cyWppx5XxV7gs/jpgkz7GkV00P/ntwtK7fbDh9t3l
NhYxrQKBgDVE4HSDqOvZOaXGRoM0pJ3uYRTTSIDGVNMZ9t2C/t3uwoyFBe+Om2t+
G6w2Gr+Dck1v+zizU3khbAHvE67rYoUtrDvae41bmLuVcnYh4UsXfhB6BWOSaQ+l
l8aQwTfmV74szsEDcFkg038zQ6Q4c8iiurYp29nwEM7/mayBGOcv
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIHEDCCBfigAwIBAgIQC53CSHjB5MGsHDzx/2AxzjANBgkqhkiG9w0BAQsFADBb
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMRowGAYDVQQDExFTZWN1cmUgU2l0ZSBDQSBHMjAeFw0y
MDA2MTAwMDAwMDBaFw0yMjA5MTIxMjAwMDBaMFsxCzAJBgNVBAYTAkNOMRAwDgYD
VQQIEwdCZWlqaW5nMSIwIAYDVQQKExlUSEggWmlqaW5nIChCZWlqaW5nKSBJbmMu
MRYwFAYDVQQDDA0qLmV6aWppbmcuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAn0EINdIXTDCzmR7J5FOjOV+PbXt7GNO6fanoCGe2O0CPRlNf2Ea/
wv6SlRtJPd0ohmnKqZdUbBpAsiV4ggOdOqeEB6utVYQWY/zhXRKYeRjN/iDuWCRY
5S+eRVkSzVOJP9DlBn6dnHSsWj55h1PrkIac8B862F/cVno/Wk5dqU55ZUoNwHGw
5Goz3R37w+Q0C9HRS5mrmPqI+Ogy8TJrIRxw9YAj5OlvuqBAeYAW1sNdEfsimMB0
H2fbbXqEL4AsipE5ppP7Ij3vxVpxvmnl/SO7N6+Fit6r25VeFSvplK+PIV3cUsK3
PCKV2sOo0BDWtWFQh5hW3fK5RYjLpNDHCwIDAQABo4IDzjCCA8owHwYDVR0jBBgw
FoAUxBF+iECGwkG/ZfMa4bRTQKOr7H0wHQYDVR0OBBYEFHxjLRRYXe2jIjYECuN8
r3EnjOTFMCUGA1UdEQQeMByCDSouZXppamluZy5jb22CC2V6aWppbmcuY29tMA4G
A1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwbwYD
VR0fBGgwZjAxoC+gLYYraHR0cDovL2NybDMuZGlnaWNlcnQuY29tL1NlY3VyZVNp
dGVDQUcyLmNybDAxoC+gLYYraHR0cDovL2NybDQuZGlnaWNlcnQuY29tL1NlY3Vy
ZVNpdGVDQUcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG/WwBATAqMCgGCCsGAQUF
BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECAjBsBggr
BgEFBQcBAQRgMF4wIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjA5
BggrBgEFBQcwAoYtaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vU2VjdXJlU2l0
ZUNBRzIuY3J0MAwGA1UdEwEB/wQCMAAwggH1BgorBgEEAdZ5AgQCBIIB5QSCAeEB
3wB2AEalVet1+pEgMLWiiWn0830RLEF0vv1JuIWr8vxw/m1HAAABcpwT21oAAAQD
AEcwRQIgWTyqiBOL3dFTJBE2Q6cgSBzk9W5iTaC2B8T1f8gFCP0CIQDhngm9WJbO
J7v14h6w+B2Li7WEAkWLSLiTKzh7na2SuQB1ACJFRQdZVSRWlj+hL/H3bYbgIyZj
rcBLf13Gg1xu4g8CAAABcpwT2zEAAAQDAEYwRAIgckmPL6WJx9Jke4AfVLmy//ye
tsmT5si8FO8p9Fd52VECICPqDvdjlN2DtfQznTGTxaL0PQ5N8eNiX3fJn6sRCfcU
AHYAUaOw9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAFynBPbfQAABAMA
RzBFAiEAwYooscdEijXGnRdJYnz0ClmvWcxtJ169Bq+sywhPReACIDjvE5a5d7mb
n3YTgfLOtbnuDpkDRjUfdY7cs6UfderhAHYAQcjKsd8iRkoQxqE6CUKHXk4xixsD
6+tLx2jwkGKWBvYAAAFynBPa0wAABAMARzBFAiAmJVwNfWFMKrqWTvEfHk9O/5/r
Crj/W3BqjV6p0D09hgIhAIKb4drMok8s1X0Evh4Nbzd3Nv9PuwITdICztemCrk4e
MA0GCSqGSIb3DQEBCwUAA4IBAQBWSrE/pt//MKeGpf6vMISGD0LZArebPFQ7wlgv
Y13HpCY5lqwrZItsuXWS5IYMv8ueYarCm081OJOBvSUKHOtYSe6wdFqsXehokUiy
7oVNief7Li5RvLcf6z5fyjB+i017dds73Dt94mE1imV1DR1WErp1U6QCMEh+TKFa
PL52V9X5VWiYdImzdm8AWOlNBrgicmVzEEQuglejF5uaALf9iiyAjP36apqXv77T
UtxKgjONB1tnRw4XRqzwrEK+QjeOhziKCn1v2ppFX/Z11YYA7ajICVrG6wGJ+ENc
ukf5+v8r+TU7PqxQmb62zocX22jhe8HM644UJ4FWCiBh4Lb1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFFjCCA/6gAwIBAgIQCH4Y+4+qkn7odgoNiYL1EjANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xOTA2MjAxMjIxMzVaFw0yOTA2MjAxMjIxMzVaMFsxCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xGjAYBgNVBAMTEVNlY3VyZSBTaXRlIENBIEcyMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAx7s903fR6SgpA08UdhKEUIZHa2Ig7KPNkTtwMS1+08YS
5QSEDM4DQxy48jP8dZkyyU9J/0WCm8Nlv5ga7HOAxhdJcv+CPP4oadx8EbdrmjAH
rGOv64oHvt7Ina7uzLd3krqxd0doeuxRpTHvFAyjaUhxjSfZx0wh1f6W7prPm7V5
0VcTudj4rI+xtHXUcFAuFz4bcapTcru5aaZ1v6F2usMCMVM+xJxEZcsUM4uTxdIf
W5FUTI0dbP8NyZkr/WVzL59aGwBE4ZU0JKBlgEmtkFpLPR7JCzYunafu7nMk5YY2
6WDOmezpWDjzDxJ8xakizykWYT5gdJYE3ULlUe31WQIDAQABo4IBzjCCAcowHQYD
VR0OBBYEFMQRfohAhsJBv2XzGuG0U0Cjq+x9MB8GA1UdIwQYMBaAFAPeUDVW0Uy7
ZvCj4hsbw5eyPdFVMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcD
AQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAxBggrBgEFBQcBAQQlMCMwIQYI
KwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjBEBgNVHR8EPTA7MDmgN6A1
hjNodHRwOi8vY3JsLmRpZ2ljZXJ0LWNuLmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD
QS5jcmwwgc4GA1UdIASBxjCBwzCBwAYEVR0gADCBtzAoBggrBgEFBQcCARYcaHR0
cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBigYIKwYBBQUHAgIwfgx8QW55IHVz
ZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2Yg
dGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50IGxvY2F0ZWQgYXQgaHR0cHM6Ly93
d3cuZGlnaWNlcnQuY29tL3JwYS11YTANBgkqhkiG9w0BAQsFAAOCAQEAE+8lW5Yw
IuiRsHn4gYRRVbLmIypWwYH74lIXnQiALeUsUkWfW7KA0ARF1el3YaTAg8/r6zyX
eZTdlhndxKOKvO5N+rnHWJB6a3fJURn6e0I+rDzKV1Zacv2Vx/ZHLZmza/bp4Azi
BrDOiPlW/Ktj6ALQzAgq70Oytk9htLupBWPuplJDdyhGqb9RfQvWc1Fa1HwXdBQi
oJPibfMaYkHMY3pTbOv2rzMKEoZwHDHqyC73RI9JgqqiXHw0rIL8A1uL3IrymXEr
mycTqbSozQwiiEfb+cxzY82YaNzaLpJyIst0T2QmdDDngmyd2LEmm4NKeXRrcFRh
XDDFfpIn93B7JA==
-----END CERTIFICATE-----
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="https://zws-imgs-pub.ezijing.com/pc/base/favicon.ico" />
<meta name="theme-color" content="#3276fc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>紫荆教育SAAS平台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "saas",
"version": "0.0.0",
"scripts": {
"dev": "vite --mode dev",
"build": "vue-tsc --noEmit && vite build --mode prod",
"build:test": "vue-tsc --noEmit && vite build --mode test",
"build:pre": "vue-tsc --noEmit && vite build --mode pre",
"preview": "vite preview",
"typecheck": "vue-tsc --noEmit",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"deploy": "node ./deploy.js"
},
"dependencies": {
"axios": "^0.26.1",
"countup.js": "^2.1.0",
"pinia": "^2.0.11",
"vue": "^3.2.31",
"vue-router": "^4.0.14"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.1.0",
"@types/node": "^16.11.26",
"@vitejs/plugin-vue": "^2.2.4",
"@vue/eslint-config-typescript": "^10.0.0",
"@vue/tsconfig": "^0.1.3",
"ali-oss": "^6.17.1",
"chalk": "^5.0.1",
"eslint": "^8.10.0",
"eslint-plugin-vue": "^8.5.0",
"sass": "^1.49.9",
"typescript": "~4.6.2",
"vite": "^2.8.6",
"vite-plugin-checker": "^0.4.2",
"vue-tsc": "^0.32.1"
}
}
<template>
<div id="app">
<router-view />
</div>
</template>
html * {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
outline: none;
-webkit-text-size-adjust: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
body,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
p,
blockquote,
dl,
dt,
dd,
ul,
ol,
li,
pre,
form,
fieldset,
legend,
button,
input,
textarea,
th,
td {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 100%;
}
ul,
ol,
li {
list-style: none;
}
em,
i {
font-style: normal;
}
strong,
b {
font-weight: normal;
}
img {
border: none;
}
input,
img {
vertical-align: middle;
}
a {
color: inherit;
text-decoration: none;
}
input,
button,
select,
textarea {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-appearance: none;
border: 0;
border-radius: 0;
font: inherit;
}
textarea:focus {
outline: 0;
}
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { CountUp } from 'countup.js'
const props = defineProps({
endVal: { type: Number, default: 0 },
options: {
type: Object,
default: () => ({
separator: ''
})
}
})
const myRef = ref('')
onMounted(() => {
const countUp = new CountUp(myRef.value, props.endVal, props.options)
if (!countUp.error) {
countUp.start()
} else {
console.error(countUp.error)
}
})
</script>
<template>
<i ref="myRef"></i>
</template>
<script setup lang="ts">
defineProps({ title: String })
</script>
<template>
<div class="app-card">
<div class="app-card-hd">
<slot name="header">
<h2 class="app-card-hd__title" v-if="title">{{ title }}</h2>
<slot name="header-aside"></slot>
</slot>
</div>
<div class="app-card-bd">
<slot></slot>
</div>
</div>
</template>
<style>
.app-card {
background: #fff;
box-shadow: 0 1px 6px 0 rgb(228 232 235 / 20%);
padding: 20px;
border-radius: 20px;
}
.app-card + .app-card {
margin-top: 20px;
}
.app-card-hd {
display: flex;
}
.app-card-hd__title {
margin-bottom: 20px;
font-size: 20px;
font-weight: 500;
padding-bottom: 10px;
border-bottom: 2px solid #aa1941;
}
</style>
<script setup lang="ts">
// function logout() {
// // this.$store.dispatch('logout').then(() => {
// // window.location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(window.location.href)}`
// // })
// }
</script>
<template>
<header class="app-header">
<div class="app-header-inner">
<div class="app-header-left">
<div class="logo">
<router-link to="/"><img src="https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo.svg" /></router-link>
</div>
<div class="app-name">紫荆教育SAAS平台</div>
</div>
<div class="app-header-right"></div>
</div>
</header>
</template>
<style lang="scss">
.app-header {
position: sticky;
top: 0;
background: #fff;
box-shadow: 0px 0px 29px rgba(0, 0, 0, 0.1);
border-top: 10px solid #aa1941;
z-index: 1000;
.logo {
width: 180px;
}
}
.app-header-inner {
max-width: 1440px;
margin: 0 auto;
padding: 0 60px;
display: flex;
align-items: center;
justify-content: space-between;
height: 100px;
color: #aa1941;
}
.app-header-left {
display: flex;
align-items: center;
.app-name {
margin-left: 40px;
padding: 0 40px;
font-size: 23px;
line-height: 26px;
font-weight: 500;
letter-spacing: 4px;
border-left: 1px solid #707070;
}
}
.app-header-right {
display: flex;
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
overflow: hidden;
}
&:hover {
background-color: rgba(60, 64, 67, 0.08);
}
}
}
.app-header-user {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 16px;
}
.app-header-user-avatar {
margin-bottom: 6px;
width: 80px;
height: 80px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.app-header-user-main {
h3 {
color: #202124;
font: 500 16px/22px Helvetica, Arial, sans-serif;
letter-spacing: 0.29px;
margin: 0;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
p {
color: #5f6368;
font: 400 14px/19px Helvetica, Arial, sans-serif;
letter-spacing: normal;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
}
.app-header-user-buttons {
padding-top: 16px;
}
</style>
<template>
<div class="app-layout">
<AppHeader></AppHeader>
<div class="app-layout-container">
<router-view></router-view>
</div>
</div>
</template>
<script setup lang="ts">
import AppHeader from './Header.vue'
</script>
<style>
.app-layout {
min-height: 100vh;
background: #f9f8f8 url('https://webapp-pub.ezijing.com/project/saas/bg.png') no-repeat center bottom;
background-size: cover;
background-attachment: fixed;
}
</style>
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import modules from './modules'
// 公共css
import './assets/css/base.css'
const app = createApp(App)
// 注册模块
modules({ router })
app.use(createPinia())
app.use(router)
app.mount('#app')
<script setup lang="ts">
import AppCard from '@/components/base/AppCard.vue'
defineProps({ data: { type: Object, default: () => ({}) } })
</script>
<template>
<AppCard :title="data.title" :class="data.className">
<div class="box">
<div class="box-left">
<div class="box-row" v-for="(row, index) in data.leftItems" :key="index">
<div class="box-cell" v-for="(cell, index) in row" :key="index">
<a :href="cell.href" target="_blank">
<div class="box-cell-icon">
<img :src="cell.icon" class="icon-normal" />
<img :src="cell.hoverIcon" class="icon-hover" />
</div>
<div class="box-cell-name">{{ cell.title }}</div>
</a>
</div>
</div>
</div>
<div class="box-right" v-if="data.rightItems">
<div class="box-row" v-for="(row, index) in data.rightItems" :key="index">
<div class="box-cell" v-for="(cell, index) in row" :key="index">
<a :href="cell.href" target="_blank">
<div class="box-cell-icon">
<img :src="cell.icon" class="icon-normal" />
<img :src="cell.hoverIcon" class="icon-hover" />
</div>
<div class="box-cell-name">{{ cell.title }}</div>
</a>
</div>
</div>
</div>
</div>
</AppCard>
</template>
<style lang="scss">
.box {
display: flex;
}
.box-left {
flex: 1;
a:hover {
color: #fff;
background-color: #aa1941;
}
}
.box-right {
flex: 1;
margin-left: 20px;
padding-left: 20px;
border-left: 1px dashed #c1c1c1;
a:hover {
color: #fff;
background-color: #136ca8;
}
}
.box-row {
display: flex;
}
.box-row + .box-row {
margin-top: 20px;
}
.box-cell {
flex: 1;
background-color: #f7f5f5;
border-radius: 20px;
color: #333;
overflow: hidden;
a {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 150px;
&:hover {
.icon-normal {
display: none;
}
.icon-hover {
display: block;
}
}
}
}
.box-cell + .box-cell {
margin-left: 20px;
}
.box-cell-icon {
height: 46px;
img {
height: 100%;
object-fit: contain;
}
.icon-normal {
display: block;
}
.icon-hover {
display: none;
}
}
.box-cell-name {
margin-top: 18px;
font-size: 16px;
font-weight: 400;
line-height: 28px;
}
.is-blue {
.app-card-hd__title {
border-color: #136ca8;
}
.box-cell {
a:hover {
color: #fff;
background-color: #136ca8;
}
}
}
</style>
<script setup lang="ts">
import CountUp from '@/components/CountUp.vue'
const list = [
{ num: 5000, name: '学生人数', more: '+' },
{ num: 700, name: '教师人数', more: '+' },
{ num: 535, unit: '门', name: '课程数量' },
{ num: 10, unit: '个', name: '国际学历/学位' },
{ num: 12, unit: '个', name: '海外合作院校' }
]
</script>
<template>
<div class="total">
<dl v-for="(item, index) in list" :key="index">
<dt>
<span><CountUp :endVal="item.num"></CountUp>{{ item.more }}</span>
<em>{{ item.unit }}</em>
</dt>
<dd>{{ item.name }}</dd>
</dl>
</div>
</template>
<style lang="scss">
.total {
display: flex;
height: 160px;
padding: 42px 0;
background: url('https://webapp-pub.ezijing.com/project/saas/top_bg.png') no-repeat center top;
background-size: cover;
dl {
flex: 1;
text-align: center;
color: #fff;
}
dl + dl {
border-left: 1px dashed #ffffff;
}
dt {
span {
font-size: 36px;
font-weight: bold;
}
em {
padding-left: 10px;
font-size: 16px;
}
}
dd {
font-size: 16px;
}
}
</style>
import AppLayout from '@/components/layout/Index.vue'
const routes = [
{
path: '/',
component: AppLayout,
children: [{ path: '', component: () => import('./views/Index.vue') }]
}
]
export { routes }
<script setup lang="ts">
import Total from '../components/Total.vue'
import Card from '../components/Card.vue'
const rows = [
[
{
title: '产业学院/专业共建',
leftItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_1.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_1_hover.png',
title: 'CMS教学资源系统',
href: 'https://course.ezijing.com/'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_2.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_2_hover.png',
title: '课程管理中心',
href: ''
}
]
],
rightItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_3.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_3_hover.png',
title: '课程学习',
href: ''
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_4.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_1_4_hover.png',
title: '在线考试',
href: ''
}
]
]
}
],
[
{
title: '技能培训中心',
leftItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_1.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_1_hover.png',
title: '1+X院校管理',
href: 'https://x-school-admin.ezijing.com'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_2.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_2_hover.png',
title: '1+X教务管理',
href: 'https://x-school.ezijing.com'
}
],
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_3.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_3_hover.png',
title: '1+X考务管理',
href: 'https://qa-center.ezijing.com/exam?project_tag=x1'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_4.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_4_hover.png',
title: '1+X教学平台',
href: 'https://x-school.ezijing.com'
}
]
],
rightItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_5.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_5_hover.png',
title: '金融产品营销实训',
href: 'https://x-training.ezijing.com'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_6.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_6_hover.png',
title: '金融产品数字化营销学习',
href: 'https://x-learning.ezijing.com'
}
],
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_7.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_7_hover.png',
title: '考试中心',
href: 'https://x-exam.ezijing.com'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_8.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_2_8_hover.png',
title: '模考练习',
href: 'https://x-learning.ezijing.com/exam/exam'
}
]
]
}
],
[
{
title: '国际在线学位',
leftItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_1.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_1_hover.png',
title: '教学管理',
href: 'https://x-school.ezijing.com'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_2.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_2_hover.png',
title: '教务管理',
href: 'https://x-school.ezijing.com'
}
],
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_3.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_3_hover.png',
title: '题库管理',
href: 'https://qa-center.ezijing.com'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_4.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_4_hover.png',
title: '考务管理',
href: 'https://qa-center.ezijing.com/exam?project_tag=x1'
}
]
],
rightItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_5.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_5_hover.png',
title: '课程学习',
href: ''
}
],
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_6.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_3_6_hover.png',
title: '在线考试',
href: ''
}
]
]
}
],
[
{
title: '国际留学',
leftItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_1.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_1_hover.png',
title: '教学管理',
href: ''
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_2.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_2_hover.png',
title: '教务管理',
href: ''
}
],
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_3.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_3_hover.png',
title: '题库管理',
href: ''
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_4.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_4_hover.png',
title: '考务管理',
href: ''
}
]
],
rightItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_5.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_5_hover.png',
title: '课程学习',
href: ''
}
],
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_6.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_4_6_hover.png',
title: '在线考试',
href: ''
}
]
]
}
],
[
{
title: '实习就业',
leftItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_5_1.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_5_1_hover.png',
title: '实习就业平台',
href: 'https://www.ezijing.com/services/employment'
}
]
]
},
{
className: 'is-blue',
title: '数字经济实验室',
leftItems: [
[
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_6_1.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_6_1_hover.png',
title: '商业数据分析实验室',
href: 'https://www.ezijing.com'
},
{
icon: 'https://webapp-pub.ezijing.com/project/saas/icon_6_2.png',
hoverIcon: 'https://webapp-pub.ezijing.com/project/saas/icon_6_2_hover.png',
title: '数字化营销平台',
href: 'https://x-training.ezijing.com'
}
]
]
}
]
]
</script>
<template>
<div class="home">
<Total></Total>
<template v-for="(row, index) in rows" :key="index">
<section class="row">
<div class="row-cell" v-for="(cell, i) in row" :key="i">
<Card :data="cell"></Card>
</div>
</section>
</template>
</div>
</template>
<style lang="scss">
.home {
max-width: 1200px;
margin: 50px auto 0;
overflow: hidden;
}
.row {
display: flex;
margin: 20px 0;
}
.row-cell {
flex: 1;
}
.row-cell + .row-cell {
margin-left: 20px;
}
</style>
const modules = Object.values(import.meta.globEager('./**/index.js'))
export default function ({ router }) {
modules.forEach(({ routes }) => {
// 注册路由
routes.forEach(route => {
router.addRoute(route)
})
})
}
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [{ path: '/:pathMatch(.*)*', redirect: '/' }]
})
export default router
import { defineStore } from 'pinia'
export const useCounterStore = defineStore({
id: 'counter',
state: () => ({
counter: 0
}),
getters: {
doubleCount: (state) => state.counter * 2
},
actions: {
increment() {
this.counter++
}
}
})
import axios from 'axios'
const httpRequest = axios.create({
timeout: 60000,
withCredentials: true
})
// 响应拦截
httpRequest.interceptors.response.use(
function (response) {
const { data } = response
// 正常返回
if (data.code === 0) {
return data
}
// 未登录
if (data.code === 4001) {
location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(location.href)}`
}
return Promise.reject(data)
},
function (error) {
if (error.response) {
const { status, message } = error.response.data
// 未登录
if (status === 403) {
location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(location.href)}`
} else {
console.error(`${status}: ${message}`)
}
} else {
console.log(error)
}
return Promise.reject(error.response || error)
}
)
export default httpRequest
{
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"references": [
{
"path": "./tsconfig.vite-config.json"
}
]
}
{
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*"],
"compilerOptions": {
"composite": true,
"types": ["node", "vitest"]
}
}
import fs from 'fs'
import path from 'path'
import { fileURLToPath, URL } from 'url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import checker from 'vite-plugin-checker'
export default defineConfig({
plugins: [checker({ eslint: { lintCommand: 'eslint "./src/**/*.{vue,js,jsx,ts,tsx}"' } }), vue()],
server: {
open: true,
host: 'dev.ezijing.com',
https: {
key: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.key')),
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论