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

init

上级
VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index
VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index
VITE_LOGIN_URL=https://login2.ezijing.com/auth/login/index
/* 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"]
}
# prp-h5
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 __dirname = path.resolve()
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/prp-h5')
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_LOGIN_URL: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
-----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, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<title>PRP私享星球</title>
<script>
;(function (win, doc) {
function resizeRoot() {
var wWidth =
screen.width > 0
? win.innerWidth >= screen.width || win.innerWidth == 0
? screen.width
: win.innerWidth
: win.innerWidth,
wFsize
wFsize = ((wWidth > 750 ? 750 : wWidth) / 375) * 50
doc.documentElement.style.fontSize = wFsize + 'px'
}
resizeRoot()
win.addEventListener('resize', resizeRoot, false)
})(window, document)
</script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
{
"name": "prp-h5",
"version": "0.0.0",
"scripts": {
"dev": "vite --mode dev",
"build": "vue-tsc --noEmit && vite build --mode prod && npm run deploy",
"build:test": "vue-tsc --noEmit && vite build --test prod",
"build:pre": "vue-tsc --noEmit && vite build --pre prod",
"preview": "vite preview --port 5050",
"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",
"pinia": "^2.0.13",
"qs": "^6.10.3",
"sass": "^1.50.0",
"swiper": "^8.1.0",
"vant": "^3.4.7",
"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.3.1",
"@vue/eslint-config-typescript": "^10.0.0",
"@vue/tsconfig": "^0.1.3",
"eslint": "^8.5.0",
"eslint-plugin-vue": "^8.2.0",
"typescript": "~4.6.3",
"vite": "^2.9.1",
"vite-plugin-checker": "^0.4.5",
"vue-tsc": "^0.33.9"
}
}
差异被折叠。
<template>
<router-view />
</template>
<style>
@import '@/assets/base.css';
</style>
import httpRequest from '@/utils/axios'
// 获取用户信息
export function getUser() {
return httpRequest.get('/api/passport/account/get-user-info')
}
// 退出登录
export function logout() {
return httpRequest.get('/api/passport/rest/logout')
}
// 获取oss token
export function getToken() {
return httpRequest.get('/api/usercenter/aliyun/assume-role')
}
// 获取oss signature
export function getSignature() {
return httpRequest.get('/api/usercenter/aliyun/get-signature')
}
// 图片上传
export function uploadFile(data: object) {
return httpRequest.post('https://webapp-pub.oss-cn-beijing.aliyuncs.com', data, {
withCredentials: false,
headers: { 'Content-Type': 'multipart/form-data' }
})
}
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;
}
body {
font-size: 14px;
color: #4e4e4e;
line-height: 1;
}
html {
font-size: 50px;
}
import AppCard from '@/components/base/AppCard.vue'
declare module 'vue' {
export interface GlobalComponents {
AppCard: typeof AppCard
}
}
<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 lang="scss">
.app-card {
margin: 0.3rem 0;
}
.app-card-hd {
display: flex;
margin-bottom: 0.18rem;
}
.app-card-hd__title {
font-size: 0.28rem;
font-weight: 600;
line-height: 1;
color: #333;
}
</style>
<script setup lang="ts"></script>
<template>
<header class="app-header">
<div class="app-header__logo">
<router-link to="/"><img src="https://webapp-pub.ezijing.com/project/prp-h5/logo.png" /></router-link>
</div>
<ul class="app-header-right">
<li>
<router-link to="/messages"
><img src="https://webapp-pub.ezijing.com/project/prp-h5/icon_message.png"
/></router-link>
</li>
<li>
<router-link to="/my"><img src="https://webapp-pub.ezijing.com/project/prp-h5/icon_user.png" /></router-link>
</li>
</ul>
</header>
</template>
<style lang="scss">
.app-header {
display: flex;
align-items: center;
padding: 0.44rem 0 0.4rem;
}
.app-header__logo {
height: 0.51rem;
img {
height: 100%;
}
}
.app-header-right {
display: flex;
align-items: center;
margin-left: auto;
li + li {
margin-left: 0.22rem;
}
img {
width: 0.27rem;
}
}
</style>
<script setup lang="ts">
import AppHeader from './Header.vue'
</script>
<template>
<div class="app-layout">
<AppHeader />
<router-view />
</div>
</template>
<style lang="scss">
.app-layout {
min-height: 100vh;
max-width: 750px;
margin: 0 auto;
background: #f3f4f8 url(https://webapp-pub.ezijing.com/project/prp-h5/bg.png) no-repeat;
background-size: 100% auto;
padding: 0 0.3rem;
box-sizing: border-box;
}
</style>
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import Vant from 'vant'
import 'vant/lib/index.css'
// 公共组件
import AppCard from '@/components/base/AppCard.vue'
import modules from './modules'
const app = createApp(App)
// 注册公共组件
app.component('AppCard', AppCard)
// 注册模块
modules({ router })
app.use(createPinia())
app.use(router)
app.use(Vant)
app.mount('#app')
import httpRequest from '@/utils/axios'
// 获取首页数据
export function getHomeData() {
return httpRequest.get('/api/prp/v1/index/index')
}
<script setup lang="ts">
interface docItem {
id: string
title: string
pv: string
}
defineProps<{ docs: Array<docItem>; videos: object[] }>()
</script>
<template>
<AppCard title="入学指南">
<div class="admission">
<div class="admission-left">
<h2>解释文档</h2>
<div class="box">
<ul>
<li v-for="item in docs" :key="item.id">
<p>{{ item.title }}</p>
<span>{{ item.pv }}</span>
<van-icon name="arrow" />
</li>
</ul>
</div>
</div>
<div class="admission-right">
<div class="box box-test">
<h2>入学评测</h2>
<p class="t1">系统专业知识</p>
<p class="t2"><a href="https://www.ezijing.com" target="_blank">去看看 ></a></p>
</div>
<div class="box box-notice">
<h2>入学通知书</h2>
<p class="t1">报名之后即可查询</p>
<p class="t2"><a href="https://www.ezijing.com" target="_blank">去看看 ></a></p>
</div>
</div>
</div>
</AppCard>
</template>
<style lang="scss">
.admission {
display: flex;
justify-content: space-between;
}
.admission-left {
padding: 0.1rem;
width: 3.33rem;
background: url(https://webapp-pub.ezijing.com/project/prp-h5/admission_bg.png) no-repeat;
background-size: contain;
box-sizing: border-box;
h2 {
margin: 0.1rem 0.1rem 0.14rem;
font-size: 0.26rem;
font-weight: 500;
line-height: 1.4;
color: #fff;
}
.box {
width: 3.13rem;
height: 3.43rem;
background: #ffffff;
border-radius: 0.1rem;
ul {
overflow: hidden;
}
li {
margin: 0.3rem 0.14rem 0;
display: flex;
align-items: center;
font-size: 0.2rem;
color: #adadad;
}
p {
flex: 1;
font-size: 0.24rem;
color: #4e4e4e;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
span {
min-width: 0.44rem;
font-size: 0.2rem;
color: #c6c6c6;
}
}
}
.admission-right {
.box {
padding: 0.22rem 0.2rem;
width: 3.33rem;
height: 2.01rem;
background: #fff;
border-radius: 0.2rem;
box-sizing: border-box;
h2 {
font-size: 0.26rem;
line-height: 1.4;
font-weight: 600;
color: #333;
}
.t1 {
margin-top: 0.14rem;
font-size: 0.22rem;
font-weight: 400;
color: #666666;
}
.t2 {
margin-top: 0.35rem;
font-size: 0.22rem;
font-weight: 400;
color: #033974;
}
}
.box + .box {
margin-top: 0.2rem;
}
.box-test {
background: #fff url(https://webapp-pub.ezijing.com/project/prp-h5/admission_1.png) no-repeat right bottom;
background-size: 50%;
}
.box-notice {
background: #fff url(https://webapp-pub.ezijing.com/project/prp-h5/admission_2.png) no-repeat right bottom;
background-size: 50%;
}
}
</style>
<script setup lang="ts">
import { Swiper, SwiperSlide } from 'swiper/vue'
import { Pagination } from 'swiper'
import 'swiper/css'
import 'swiper/css/pagination'
const list: Array<{
url: string
imageUrl: string
}> = [
{
url: '/',
imageUrl: 'https://webapp-pub.ezijing.com/project/prp-h5/banner.png'
},
{
url: '/',
imageUrl: 'https://webapp-pub.ezijing.com/project/prp-h5/banner.png'
},
{
url: '/',
imageUrl: 'https://webapp-pub.ezijing.com/project/prp-h5/banner.png'
}
]
</script>
<template>
<nav class="home-banner">
<Swiper pagination :modules="[Pagination]">
<SwiperSlide v-for="(item, index) in list" :key="index">
<img :src="item.imageUrl" />
</SwiperSlide>
</Swiper>
</nav>
</template>
<style lang="scss">
.home-banner {
border-radius: 0.2rem;
overflow: hidden;
img {
width: 100%;
height: 3.2rem;
}
.swiper-pagination-bullet {
background: #fff;
}
.swiper-pagination-bullet-active {
background: #fff;
}
}
</style>
<script setup lang="ts"></script>
<template>
<AppCard title="考试攻略"></AppCard>
</template>
<script setup lang="ts"></script>
<template>
<AppCard title="学习地图"></AppCard>
</template>
<script setup lang="ts">
import { Swiper, SwiperSlide } from 'swiper/vue'
import 'swiper/css'
const menus: Array<{
name: string
path: string
icon: string
}> = [
{
path: '/',
name: '入学指南',
icon: 'https://webapp-pub.ezijing.com/project/prp-h5/home_menu_1.png'
},
{
path: '/',
name: '学习地图',
icon: 'https://webapp-pub.ezijing.com/project/prp-h5/home_menu_2.png'
},
{
path: '/',
name: '权益查看',
icon: 'https://webapp-pub.ezijing.com/project/prp-h5/home_menu_3.png'
},
{
path: '/',
name: '荣誉总榜',
icon: 'https://webapp-pub.ezijing.com/project/prp-h5/home_menu_4.png'
},
{
path: '/',
name: '伴随问答',
icon: 'https://webapp-pub.ezijing.com/project/prp-h5/home_menu_5.png'
},
{
path: '/',
name: '考试攻略',
icon: 'https://webapp-pub.ezijing.com/project/prp-h5/home_menu_6.png'
}
]
</script>
<template>
<nav class="home-nav">
<swiper slides-per-view="auto" :space-between="12">
<swiper-slide v-for="(item, index) in menus" :key="index" class="nav-item">
<img :src="item.icon" />
<p>{{ item.name }}</p>
</swiper-slide>
</swiper>
</nav>
</template>
<style lang="scss">
.home-nav {
margin-top: 0.3rem;
text-align: center;
.nav-item {
width: 1.2rem;
}
img {
width: 1.2rem;
height: 1.2rem;
}
p {
font-size: 0.24rem;
}
}
</style>
<script setup lang="ts"></script>
<template>
<AppCard title="荣誉总榜"></AppCard>
</template>
import type { RouteRecordRaw } from 'vue-router'
import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: AppLayout,
children: [{ path: '', component: () => import('./views/Index.vue') }]
}
]
<script setup lang="ts">
import { ref } from 'vue'
import * as api from '../api'
import HomeBanner from '../components/Banner.vue'
import HomeMenu from '../components/Menu.vue'
import AdmissionGuide from '../components/AdmissionGuide.vue'
import LearningMap from '../components/LearningMap.vue'
import ExamStrategy from '../components/ExamStrategy.vue'
import TeamRanking from '../components/TeamRanking.vue'
const data = ref<{ banner: object[]; admission_guide_docs: object[]; admission_guide_videos: object[] }>({
banner: [],
admission_guide_docs: [],
admission_guide_videos: []
})
// 获取首页数据
function fetchHomeData() {
api.getHomeData().then(res => {
data.value = res.data
})
}
fetchHomeData()
</script>
<template>
<HomeBanner :list="data.banner"></HomeBanner>
<HomeMenu></HomeMenu>
<!-- 入学指南 -->
<AdmissionGuide :docs="data.admission_guide_docs" :videos="data.admission_guide_videos"></AdmissionGuide>
<!-- 学习地图 -->
<LearningMap></LearningMap>
<!-- 权益查看 -->
<!-- 荣誉总榜 -->
<TeamRanking></TeamRanking>
<!-- 考试攻略 -->
<ExamStrategy></ExamStrategy>
<!-- 陪伴问答 -->
</template>
import type { Router, RouteRecordRaw } from 'vue-router'
export default function ({ router }: { router: Router }) {
const modules: Array<{ routes: Array<RouteRecordRaw> }> = Object.values(import.meta.globEager('./**/index.ts'))
modules.forEach(({ routes = [] }) => {
// 注册路由
routes.forEach(route => {
router.addRoute(route)
})
})
}
import type { RouteRecordRaw } from 'vue-router'
import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [
{
path: '/messages',
component: AppLayout,
children: [{ path: '', component: () => import('./views/Index.vue') }]
}
]
<script setup lang="ts"></script>
<template>
<div class="home"></div>
</template>
import type { RouteRecordRaw } from 'vue-router'
import AppLayout from '@/components/layout/Index.vue'
export const routes: Array<RouteRecordRaw> = [
{
path: '/my',
component: AppLayout,
children: [{ path: '', component: () => import('./views/Index.vue') }]
}
]
<script setup lang="ts"></script>
<template>
<div class="home"></div>
</template>
import { createRouter, createWebHistory } from 'vue-router'
// import { useUserStore } from '@/stores/user'
const router = createRouter({
scrollBehavior() {
// 始终滚动到顶部
return { top: 0 }
},
history: createWebHistory(),
routes: [{ path: '/:pathMatch(.*)*', redirect: '/' }]
})
// router.beforeEach((to, from, next) => {
// const user = useUserStore()
// user.getUser()
// next()
// })
export default router
import { defineStore } from 'pinia'
import { getUser, logout } from '@/api/base'
interface IUserState {
id: string
avatar: string
mobile: string
realname: string
nickname: string
username: string
}
export const useUserStore = defineStore({
id: 'user',
state: () => {
return {
user: null as IUserState | null
}
},
getters: {
isLogin: state => !!state.user,
userName: ({ user }) => {
if (!user) return ''
return user.realname || user.nickname || user.username || ''
}
},
actions: {
async getUser() {
const res = await getUser()
this.user = res.data
},
async logout() {
await logout()
this.user = null
}
}
})
import axios from 'axios'
const httpRequest = axios.create({
// baseURL: 'https://learn-api.ezijing.com',
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/*"]
},
"lib": ["DOM", "ESNext"]
},
"references": [
{
"path": "./tsconfig.vite-config.json"
}
]
}
{
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*"],
"compilerOptions": {
"composite": true,
"types": ["node"]
}
}
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(({ mode }) => {
return {
base: mode === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/prp-h5/' : '/',
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'))
},
proxy: {
'/api/prp': {
target: 'http://localhost-sixiangxingqiu-frontend.ezijing.com',
changeOrigin: true,
rewrite: path => path.replace('/api/prp/', '/')
},
'/api': 'https://learn-api.ezijing.com'
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
css: {
// 禁用SASS警告提醒
preprocessorOptions: { scss: { charset: false } }
}
}
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论