Compare commits
10 Commits
c0a8a9cd95
...
024f306636
| Author | SHA1 | Date | |
|---|---|---|---|
| 024f306636 | |||
| 4da6832b44 | |||
| bef1906747 | |||
| f501c6041b | |||
| 4058cf584c | |||
| c086b91c1f | |||
| b33663b2f0 | |||
| efdf92990b | |||
| 873fdeffc9 | |||
| 67c4658f6b |
@@ -0,0 +1,46 @@
|
|||||||
|
# ============== 环境变量模板 ==============
|
||||||
|
# 复制为 .env.development / .env.production / .env.test 后填入真实值。
|
||||||
|
# 真实值不要 commit 到 git。
|
||||||
|
|
||||||
|
# 当前模式名(dev / test / prod)
|
||||||
|
VITE_MODE_NAME=development
|
||||||
|
|
||||||
|
# 资源 CDN 前缀
|
||||||
|
VITE_RES_URL=http://localhost:5173/
|
||||||
|
|
||||||
|
# 后端 API 基础地址
|
||||||
|
# ⚠️ 本地必须写前端自己(http://localhost:5173),由 Vite proxy 转发
|
||||||
|
# 写 http://localhost:8080/auth 会让浏览器绕过 proxy 直连 8080
|
||||||
|
# dev: http://localhost:5173
|
||||||
|
# dev (K8s): https://dev.violin-home.cn
|
||||||
|
# prod: https://www.violin-home.cn
|
||||||
|
VITE_APP_URL=http://localhost:5173
|
||||||
|
|
||||||
|
# 应用元信息
|
||||||
|
VITE_APP_TITLE=violin-home
|
||||||
|
VITE_APP_ID=123456
|
||||||
|
VITE_AGENT_ID=123456
|
||||||
|
|
||||||
|
# 是否启用 mock(dev 启用,prod 关闭)
|
||||||
|
VITE_LOGIN_TEST=true
|
||||||
|
|
||||||
|
# ============== OIDC / Authentik 配置 ==============
|
||||||
|
# 三个环境的 issuer + client-id + redirect-uri 都不一样。
|
||||||
|
# dev 与 prod 必须用 Authentik 后台两个独立的 Application,
|
||||||
|
# 因为 redirect-uri 不同(dev 走 localhost,prod 走域名)。
|
||||||
|
|
||||||
|
# Authentik 域名(dev / prod 共用,dev 仅用于登录页跳转)
|
||||||
|
VITE_OIDC_ISSUER=https://auth.violin-work.online
|
||||||
|
|
||||||
|
# 客户端 ID(在 Authentik 后台创建)
|
||||||
|
# dev: violin-home-dev
|
||||||
|
# prod: violin-home
|
||||||
|
VITE_OIDC_CLIENT_ID=
|
||||||
|
|
||||||
|
# 回调 URI(必须与 Authentik 后台配置的完全一致)
|
||||||
|
# dev: http://localhost:5173/auth/callback
|
||||||
|
# prod: https://www.violin-home.cn/auth/callback
|
||||||
|
VITE_OIDC_REDIRECT_URI=
|
||||||
|
|
||||||
|
# 编辑器标识
|
||||||
|
VITE_EDITOR=vscode
|
||||||
@@ -9,10 +9,17 @@ lerna-debug.log*
|
|||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
dist-ssr
|
dist-ssr
|
||||||
|
dist
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
|
# 临时文件
|
||||||
|
tmp/
|
||||||
|
.opencode/
|
||||||
|
.opencode/tmp/
|
||||||
|
|
||||||
# 配置文件信息不能暴露
|
# 配置文件信息不能暴露
|
||||||
.env.*
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
@@ -0,0 +1,210 @@
|
|||||||
|
# AGENT.md — violin-home
|
||||||
|
|
||||||
|
> 面向 AI agent 的工程导览:模块关系、路由约定、与后端的契约、扩展点。
|
||||||
|
> 代码即事实,本文件是索引;如代码与本文档冲突,**以代码为准**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目定位
|
||||||
|
|
||||||
|
violin-home 是 **violin 微服务套件的统一前端门户**,部署在 `https://www.violin-home.cn/`。
|
||||||
|
|
||||||
|
- 认证:**Authentik OIDC**,回调路径 `/auth/callback`,前端把 code POST 到 `violin-auth` 服务换 token
|
||||||
|
- 后端:依赖 violin-auth(认证)/ violin-bookmark(书签)/ violin-calendar(日历)/ violin-onenote / violin-cloud / 等子服务
|
||||||
|
- 域名:生产 `https://www.violin-home.cn/`;本地 dev 走 `.env.development` 的 `VITE_APP_URL`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
| 维度 | 选型 |
|
||||||
|
|------|------|
|
||||||
|
| 框架 | Vue 3.5 + Composition API (`<script setup>`) |
|
||||||
|
| 构建 | Vite 5 |
|
||||||
|
| 语言 | TypeScript 5.6 |
|
||||||
|
| UI | Element Plus 2.8 + Icons |
|
||||||
|
| 状态 | Pinia 2.2 |
|
||||||
|
| 路由 | vue-router 4.4(**memory history**,不是 hash / web) |
|
||||||
|
| HTTP | axios 1.7 |
|
||||||
|
| 图表 | ECharts 5 |
|
||||||
|
| Markdown | md-editor-v3 4 |
|
||||||
|
| 日期 | dayjs(**已废弃 moment**) |
|
||||||
|
| Mock | vite-plugin-mock 3(**仅 dev 启用**) |
|
||||||
|
| 拖拽 | vuedraggable 4 |
|
||||||
|
| 样式 | SCSS(Dart Sass 1.79,**已删除 node-sass**) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
violin-home/
|
||||||
|
├── public/ 静态资源(不打包)
|
||||||
|
│ ├── blog/*.ts 博客元数据(按业务模块拆分)
|
||||||
|
│ └── reset/ Authentik reset 入口(reset.html 等)
|
||||||
|
├── src/
|
||||||
|
│ ├── api/ axios 接口封装(每个业务一个文件)
|
||||||
|
│ ├── components/ 公共组件
|
||||||
|
│ │ ├── common/ 通用组件
|
||||||
|
│ │ ├── layout/ 顶层布局
|
||||||
|
│ │ ├── login/ 登录 / 注册 / sorryPage
|
||||||
|
│ │ ├── cloud/ 云盘 + aplayer 音乐
|
||||||
|
│ │ ├── illustration/ 插画
|
||||||
|
│ │ ├── customPic/ 自定义图片
|
||||||
|
│ │ └── operate/ 操作组件
|
||||||
|
│ ├── const/ 全局常量
|
||||||
|
│ ├── entity/ 实体类型(TypeScript interface)
|
||||||
|
│ ├── router/ 路由表(**统一指向 @/view/**)
|
||||||
|
│ ├── service/ 服务层(独立于 axios 的工具服务)
|
||||||
|
│ ├── store/ Pinia stores
|
||||||
|
│ ├── style/ 全局样式(mixin.scss 在 vite.config.ts 里自动注入)
|
||||||
|
│ ├── types/ 类型声明(*.d.ts)
|
||||||
|
│ ├── utils/ 工具函数(auth 令牌管理、request axios 封装、date、number)
|
||||||
|
│ ├── view/ **页面视图(业务页)** — 单数 view
|
||||||
|
│ ├── App.vue
|
||||||
|
│ ├── env.d.ts
|
||||||
|
│ ├── main.ts
|
||||||
|
│ └── permission.ts 路由守卫
|
||||||
|
├── mock/ vite-plugin-mock 的 mock 数据
|
||||||
|
├── authentik-deploy/ Authentik 部署相关(helm values、reset 脚本)
|
||||||
|
├── .env.development 本地开发
|
||||||
|
├── .env.test 测试环境
|
||||||
|
├── .env.production 生产环境
|
||||||
|
├── Dockerfile
|
||||||
|
├── Jenkinsfile
|
||||||
|
├── nginx.conf
|
||||||
|
├── vite.config.ts
|
||||||
|
└── tsconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 路由约定
|
||||||
|
|
||||||
|
**全部路由指向 `@/view/`**(单数),包括 `/auth/callback`:
|
||||||
|
- `router/index.ts` 是**唯一**的路由表
|
||||||
|
- 路由 meta.name 是侧边栏展示的中文名
|
||||||
|
- `/auth/callback` 由 `view/auth/callback.vue` 处理 OIDC 回调(拿 code → POST `/auth/oidc/callback` 到 violin-auth → 存 token)
|
||||||
|
|
||||||
|
**禁止**新建 `views/`(复数)目录。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 认证流程(OIDC)
|
||||||
|
|
||||||
|
```
|
||||||
|
浏览器 → Authentik 登录页(不在本工程)
|
||||||
|
↓ 回调到 https://www.violin-home.cn/auth/callback?code=...&state=...
|
||||||
|
↓
|
||||||
|
view/auth/callback.vue
|
||||||
|
↓ POST { code, redirect_uri } → VITE_APP_URL + '/auth/oidc/callback'
|
||||||
|
↓
|
||||||
|
violin-auth 服务(cn.violin.auth.service.OAuthService.oidcAuthorize)
|
||||||
|
↓ 返回 { token, user_id, name }
|
||||||
|
↓
|
||||||
|
utils/auth.setToken / setTenant 存到 cookie + localStorage
|
||||||
|
↓ 跳到 /
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键约定**:
|
||||||
|
- `redirect_uri` 必须和 Authentik 应用的配置完全一致(`VITE_OIDC_REDIRECT_URI`)
|
||||||
|
- `state` 必须校验(防 CSRF),前后端都用 `sessionStorage.oidc_state` 缓存
|
||||||
|
- token 由 `setToken()` 存到 cookie(`js-cookie`),后续 axios 请求拦截器自动加 `Authorization: Bearer <token>`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## HTTP 封装(utils/request.ts)
|
||||||
|
|
||||||
|
- `baseURL` = `import.meta.env.VITE_APP_URL`
|
||||||
|
- 请求拦截器:从 `js-cookie` 读 token,加到 header
|
||||||
|
- 响应拦截器:401 → 跳 `/login`;5xx → ElMessage 报错
|
||||||
|
|
||||||
|
每个业务模块在 `src/api/` 下有自己的文件(如 `api/bookmark.ts`),导出按业务分组的函数:
|
||||||
|
```ts
|
||||||
|
import { service } from '@/utils/request'
|
||||||
|
export const getBookmarks = (params: PageQuery) =>
|
||||||
|
service({ url: '/api/v1/bookmark', method: 'get', params })
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 状态管理(Pinia)
|
||||||
|
|
||||||
|
`src/store/` 下每个业务一个 store(settings、strategy、table、tenant)。**禁止**把所有状态塞进一个 store。
|
||||||
|
|
||||||
|
- `tenant` store 管当前 customer(对应后端的 customerId)
|
||||||
|
- `settings` store 管用户偏好
|
||||||
|
- `strategy` store 管 CTA 策略模板
|
||||||
|
- `table` store 管通用表格筛选/分页状态
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 与后端子服务的对应
|
||||||
|
|
||||||
|
| 路径前缀 | 后端服务 | 端口(K8s 内) |
|
||||||
|
|---------|---------|--------------|
|
||||||
|
| `/auth/**` | violin-auth | 8080 |
|
||||||
|
| `/api/v1/bookmark/**` | violin-bookmark | 8081 |
|
||||||
|
| `/api/v1/calendar/**` | violin-calendar | 8082 |
|
||||||
|
| `/api/v1/onenote/**` | violin-onenote | 8083 |
|
||||||
|
| `/api/v1/cloud/**` | violin-cloud | 8084 |
|
||||||
|
| `/api/v1/trader/**` | violin-trader | 8085 |
|
||||||
|
| `/api/v1/user/**` | violin-auth(user 模块) | 8080 |
|
||||||
|
|
||||||
|
路由由 K8s ingress 统一反向代理;前端只关心 `VITE_APP_URL` 单一域名。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 构建与运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安装依赖(推荐 pnpm,yarn 也行)
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 本地 dev(启动 mock)
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# 生产构建(先类型检查,再打包)
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# 测试环境构建
|
||||||
|
npm run build:test
|
||||||
|
|
||||||
|
# 预览构建产物
|
||||||
|
npm run preview
|
||||||
|
```
|
||||||
|
|
||||||
|
Node:v18+(**不要**用 v14/16,老的 sass-loader/node-sass 不兼容)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 已知坑(不要"清理"它们)
|
||||||
|
|
||||||
|
### 1. `view/` 单数 vs `views/` 复数
|
||||||
|
|
||||||
|
**永远只创建 `view/` 单数目录**。`views/` 是历史遗物,已删除过又留下空目录。
|
||||||
|
|
||||||
|
### 2. node-sass 已废弃
|
||||||
|
|
||||||
|
`package.json` 里**没有** `node-sass`。如果你看到 `npm install` 报 `node-sass` 相关错误,是因为旧依赖被缓存,**不要**手动加回 `node-sass`,用 Dart Sass(`sass: ^1.79`)即可。
|
||||||
|
|
||||||
|
### 3. axios 0.x → 1.x
|
||||||
|
|
||||||
|
升级到 axios 1.7 后,`axios.create()` 配置有少量变化(如 `paramsSerializer`)。如果你看到 `interceptor is not a function` 之类的报错,看下拦截器是否还兼容旧签名。
|
||||||
|
|
||||||
|
### 4. Vue Router 4 用 memory history
|
||||||
|
|
||||||
|
`createMemoryHistory()` 而非 `createWebHistory()` / `createWebHashHistory()`。刷新页面会丢路由——如果要做刷新保留路由,需要切到 `createWebHistory()` 并配合 K8s ingress 重写。
|
||||||
|
|
||||||
|
### 5. vite-plugin-mock 仅 dev 启用
|
||||||
|
|
||||||
|
生产构建不会带 mock(`localEnabled: command === 'serve'`)。如果发现生产缺数据,看下是不是依赖了 mock。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关项目
|
||||||
|
|
||||||
|
- `violin-auth` — 认证服务(OIDC + JWT 签发)
|
||||||
|
- `violin-bookmark` / `violin-calendar` / `violin-onenote` / `violin-cloud` / `violin-trader` — 业务子服务
|
||||||
|
- `violin-common` / `violin-core` — 后端共享框架
|
||||||
|
- `violin-parent` — 后端父 POM
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM nginx:1.23.1-alpine
|
FROM ccr.ccs.tencentyun.com/violin/nginx:latest
|
||||||
|
|
||||||
COPY dist /usr/share/nginx/html
|
COPY dist /usr/share/nginx/html
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# ========== Secret(密码管理)============
|
||||||
|
# ⚠️ 生产环境请使用真正随机的密码
|
||||||
|
# 生成随机密码: python3 -c "import secrets; print(secrets.token_urlsafe(32))"
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: authentik-secrets
|
||||||
|
namespace: global
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
# PostgreSQL 数据库密码
|
||||||
|
postgres-password: "你的postgres密码"
|
||||||
|
# Secret Key(用于加密 session、token 等)
|
||||||
|
authentik-secret-key: "你的随机密钥(至少32字符)"
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# ========== 5. Ingress 配置 ==========
|
||||||
|
# 使用 cert-manager 自动管理 Let's Encrypt 证书
|
||||||
|
# 如未安装 cert-manager: kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: authentik
|
||||||
|
namespace: auth
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: "nginx"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- auth.violin-work.online
|
||||||
|
secretName: authentik-tls
|
||||||
|
rules:
|
||||||
|
- host: auth.violin-work.online
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: authentik-server
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
# 如果没有 cert-manager,用这个 ClusterIssuer(先安装 cert-manager)
|
||||||
|
# apiVersion: cert-manager.io/v1
|
||||||
|
# kind: ClusterIssuer
|
||||||
|
# metadata:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# spec:
|
||||||
|
# acme:
|
||||||
|
# server: https://acme-v02.api.letsencrypt.org/directory
|
||||||
|
# email: YOUR_EMAIL@domain.com # ⚠️ 改成你的邮箱
|
||||||
|
# privateKeySecretRef:
|
||||||
|
# name: letsencrypt-prod
|
||||||
|
# solvers:
|
||||||
|
# - http01:
|
||||||
|
# ingress:
|
||||||
|
# class: nginx
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Ingress - 只暴露 server 服务,worker 不需要对外访问
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: authentik
|
||||||
|
namespace: global
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: "nginx"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- auth.violin-work.online
|
||||||
|
secretName: authentik-tls
|
||||||
|
rules:
|
||||||
|
- host: auth.violin-work.online
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: authentik-server
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# Authentik 部署指南
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
authentik-deploy/
|
||||||
|
├── 00-ns.yaml # Namespace
|
||||||
|
├── 01-postgres.yaml # PostgreSQL 数据库
|
||||||
|
├── 02-secret.yaml # 密钥(密码)
|
||||||
|
├── auth-helm-values.yaml # Authentik Helm 配置
|
||||||
|
├── 03-ingress.yaml # Ingress + TLS 证书
|
||||||
|
├── install.sh # 一键安装脚本
|
||||||
|
└── README.md # 本文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 部署步骤
|
||||||
|
|
||||||
|
### 1. 准备
|
||||||
|
|
||||||
|
确保集群已安装:
|
||||||
|
- **Helm 3**
|
||||||
|
- **cert-manager**(自动管理 HTTPS 证书)
|
||||||
|
```bash
|
||||||
|
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 修改配置
|
||||||
|
|
||||||
|
编辑 `02-secret.yaml`,替换为真实随机密码:
|
||||||
|
```bash
|
||||||
|
# 生成随机密码
|
||||||
|
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
|
||||||
|
```
|
||||||
|
将输出填入 `authentik-secret-key` 和 `postgres-password`。
|
||||||
|
|
||||||
|
编辑 `03-ingress.yaml`,将 `YOUR_EMAIL@domain.com` 替换为你的邮箱。
|
||||||
|
|
||||||
|
### 3. 执行部署
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd authentik-deploy
|
||||||
|
chmod +x install.sh
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
或手动按顺序执行:
|
||||||
|
```bash
|
||||||
|
kubectl create ns auth
|
||||||
|
kubectl apply -f 00-ns.yaml
|
||||||
|
kubectl apply -f 01-postgres.yaml
|
||||||
|
kubectl apply -f 02-secret.yaml
|
||||||
|
helm repo add authentik https://charts.goauthentik.io && helm repo update
|
||||||
|
helm install authentik authentik/authentik -n auth -f auth-helm-values.yaml
|
||||||
|
kubectl apply -f 03-ingress.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 初始化
|
||||||
|
|
||||||
|
部署完成后访问:
|
||||||
|
- **首次设置**: https://auth.violin-work.online/if/flow/initial/
|
||||||
|
- 设置管理员账号和密码
|
||||||
|
|
||||||
|
### 5. 验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n auth
|
||||||
|
kubectl logs -n auth -l app.kubernetes.io/component=server --tail=20
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 后续:配置其他服务接入 Authentik(OIDC)
|
||||||
|
|
||||||
|
### 在 Authentik 中创建 Application
|
||||||
|
|
||||||
|
1. 登录 Authentik Admin → **Applications**
|
||||||
|
2. 点击 **Create**:
|
||||||
|
- **Name**: OpenViking(或任意名称)
|
||||||
|
- **Slug**: openviking
|
||||||
|
- **Provider**: 创建 OIDC Provider(见下方)
|
||||||
|
3. 创建 Provider:
|
||||||
|
- **Name**: OpenViking Provider
|
||||||
|
- **Client ID**: openviking
|
||||||
|
- **Client Secret**: 生成一个随机值
|
||||||
|
- **Redirect URIs**: `https://viking.violin-work.online/-/oauth-callback/openviking/`(根据实际调整)
|
||||||
|
|
||||||
|
### OpenViking 配置 OIDC
|
||||||
|
|
||||||
|
在 OpenViking 的配置文件中加入:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"oidc": {
|
||||||
|
"issuer": "https://auth.violin-work.online",
|
||||||
|
"client_id": "openviking",
|
||||||
|
"client_secret": "你的client_secret"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### KubeSphere 配置 OIDC
|
||||||
|
|
||||||
|
在 KubeSphere Web 控制台:
|
||||||
|
- **平台管理 → 访问控制 → 企业设置 → 第三方登录**
|
||||||
|
- 填入 Authentik 的 OIDC 信息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 维护
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 更新 Authentik
|
||||||
|
helm repo update && helm upgrade authentik authentik/authentik -n auth -f auth-helm-values.yaml
|
||||||
|
|
||||||
|
# 卸载
|
||||||
|
helm uninstall authentik -n auth && kubectl delete ns auth
|
||||||
|
```
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Authentik Helm - 2026.5.3 腾讯云镜像配置
|
||||||
|
|
||||||
|
global:
|
||||||
|
image:
|
||||||
|
repository: ccr.ccs.tencentyun.com/tei_agent/authentik-server
|
||||||
|
tag: "2026.5.3"
|
||||||
|
|
||||||
|
authentik:
|
||||||
|
secret_key: "Mb83201048"
|
||||||
|
postgresql:
|
||||||
|
host: "192.168.3.49"
|
||||||
|
port: 5432
|
||||||
|
name: "authentik"
|
||||||
|
user: "authentik"
|
||||||
|
password: "authentik"
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 5Gi
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
server:
|
||||||
|
replicas: 1
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
worker:
|
||||||
|
replicas: 1
|
||||||
|
|
||||||
|
geoip:
|
||||||
|
enabled: false
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# ========== 一键安装脚本(Linux/macOS)============
|
||||||
|
# 保存为 install.sh,执行: chmod +x install.sh && ./install.sh
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
EMAIL="admin@violin-work.online" # ⚠️ 改成你的邮箱(Let's Encrypt 通知用)
|
||||||
|
DOMAIN="auth.violin-work.online" # ⚠️ 改成你的域名
|
||||||
|
|
||||||
|
echo "=== 1. 创建 namespace ==="
|
||||||
|
kubectl create ns auth --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
echo "=== 2. 创建 Secret ==="
|
||||||
|
kubectl apply -f 02-secret.yaml
|
||||||
|
|
||||||
|
echo "=== 3. 部署 PostgreSQL ==="
|
||||||
|
kubectl apply -f 01-postgres.yaml
|
||||||
|
|
||||||
|
echo "=== 4. 等待 PostgreSQL 就绪 ==="
|
||||||
|
kubectl wait --for=condition=ready pod -l app=authentik-postgres -n auth --timeout=120s
|
||||||
|
|
||||||
|
echo "=== 5. 添加 Helm 源并安装 Authentik ==="
|
||||||
|
helm repo add authentik https://charts.goauthentik.io --force-update
|
||||||
|
helm repo update
|
||||||
|
helm install authentik authentik/authentik -n auth -f auth-helm-values.yaml
|
||||||
|
|
||||||
|
echo "=== 6. 部署 Ingress + 证书 ==="
|
||||||
|
kubectl apply -f 03-ingress.yaml
|
||||||
|
|
||||||
|
echo "=== 7. 等待 Authentik Server 就绪 ==="
|
||||||
|
kubectl wait --for=condition=ready pod -l app.kubernetes.io/component=server -n auth --timeout=180s
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 部署完成! ==="
|
||||||
|
echo "访问: https://$DOMAIN"
|
||||||
|
echo "初始设置: https://$DOMAIN/if/flow/initial/"
|
||||||
|
echo ""
|
||||||
|
echo "查看状态:"
|
||||||
|
echo " kubectl get pods -n auth"
|
||||||
|
echo " kubectl logs -n auth -l app.kubernetes.io/component=server --tail=50"
|
||||||
Vendored
-10
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{D as e}from"./index.9e912d9b.js";import{l as i}from"./index.26aa7e8a.js";const t={"Content-Type":"application/json;charsetset=UTF-8"},l=r=>e({url:"/wiki/api/v1/reader/blogs",method:"GET",params:r,paramsSerializer:a=>i.stringify(a,{arrayFormat:"repeat"})}),p=()=>e({url:"/wiki/api/v1/reader/blog_type",method:"GET",headers:t}),n=r=>e({url:"/wiki/api/v1/reader/blog/"+r,method:"GET",headers:t}),u=()=>e({url:"/wiki/api/v1/reader/blogs/publish/all",method:"GET"}),g=r=>e({url:"/wiki/api/v1/reader/blogs/publish/"+r,method:"GET"});export{p as a,g as b,n as c,l as g,u as p};
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{D as r}from"./index.9e912d9b.js";import{l as t}from"./index.26aa7e8a.js";const m=o=>r({url:"/bookmark/api/v1/bookmark",method:"GET",params:o,paramsSerializer:a=>t.stringify(a,{arrayFormat:"repeat"})}),s=o=>r({url:"/bookmark/api/v1/bookmark/insert",method:"PUT",data:o}),b=o=>r({url:"/bookmark/api/v1/bookmark/update",method:"POST",data:o}),u=o=>r({url:"/bookmark/api/v1/bookmark/delete/"+o,method:"DELETE"}),n=()=>r({url:"/bookmark/api/v1/bookmark/count",method:"GET"});export{n as b,u as d,s as p,m as s,b as u};
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.b_section[data-v-f8c4f944],.bt_section[data-v-f8c4f944],.c_section[data-v-f8c4f944]{display:flex;flex-direction:column;align-items:stretch;border-right:1px solid royalblue}.title_style[data-v-f8c4f944]{display:flex}.title_style[data-v-f8c4f944] .el-input__inner{flex-direction:row;height:50px;font-size:20px;border-right:0px;border-left:0px;border-radius:0;border-top:1px solid royalblue;border-bottom:1px solid royalblue}.blog_editer[data-v-f8c4f944]{display:flex}.item_header[data-v-f8c4f944]{display:flex;align-items:center;border-top:1px solid royalblue;border-bottom:1px solid royalblue}.item_header_button[data-v-f8c4f944]{border:0px;height:50px}.side_bar[data-v-f8c4f944]{display:flex;align-items:center;justify-content:flex-start;width:20px}.item[data-v-f8c4f944]{padding:0;margin-top:3px;margin-bottom:3px;display:flex;height:50px;flex-direction:row;align-items:center;justify-items:center;user-select:none;border:0px;border-bottom:1px}.item>label[data-v-f8c4f944]{color:#333;height:50px;width:15px}.item>label[data-v-f8c4f944]:hover{cursor:move}.item>div[data-v-f8c4f944]{display:flex;flex-direction:column;align-items:flex-end;border:0px}.operate_button[data-v-f8c4f944]{border-color:#fff;width:20px;border:0px}.bt-input[data-v-f8c4f944]{margin:0;border:0px;padding-left:0;padding-right:5px;font-size:15px;overflow:hidden;line-height:50px;height:50px;width:100px;flex-grow:1;cursor:pointer;white-space:nowrap;text-overflow:ellipsis}.bt-input[data-v-f8c4f944]:hover{background-color:#ebebeb}.item>p[data-v-f8c4f944]{padding:6px 10px;color:#8e3333}.chosenClass[data-v-f8c4f944]{opacity:1;border:solid 1px red}.ghost[data-v-f8c4f944]{border:solid 1px rgb(19,41,239)!important}
|
|
||||||
BIN
Binary file not shown.
Vendored
-10
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
Vendored
-1
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{D as r}from"./index.9e912d9b.js";const a=()=>r({url:"/trader/api/v1/strategy_file",method:"GET"}),s=()=>r({url:"/trader/api/v1/strategy_file/load",method:"GET"}),o=t=>r({url:"/trader/api/v1/strategy_file/"+t,method:"PUT"}),i=t=>r({url:"/trader/api/v1/strategy_file/"+t,method:"PATCH"}),d=t=>r({url:"/trader/api/v1/strategy_file/"+t,method:"DELETE"}),g=()=>r({url:"/trader/api/v1/strategies",method:"GET"}),n=t=>r({url:"/trader/api/v1/strategy/"+t.strategy_name,method:"POST",data:t}),l=t=>r({url:"/trader/api/v1/strategy/init/"+t,method:"PUT"}),u=t=>r({url:"/trader/api/v1/strategy/"+t,method:"PUT"}),_=t=>r({url:"/trader/api/v1/strategy/"+t,method:"PATCH"}),y=t=>r({url:"/trader/api/v1/strategy/"+t,method:"DELETE"});export{s as a,g as b,n as c,_ as d,y as e,a as g,l as i,o as l,d as r,u as s,i as u};
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
.el-button--text[data-v-19ae7838]{margin-right:15px}.el-select[data-v-19ae7838],.el-input[data-v-19ae7838]{width:300px}.dialog-footer button[data-v-19ae7838]:first-child{margin-right:10px}
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
import{g as I,l as V,u as N,r as S}from"./cta_strategy.cff46c25.js";import{d as T,c as $,b as R,f as _,h as e,w as s,u as t,a0 as P,V as W,a1 as M,e as i,o as n,a2 as g,a3 as u,B as m,a4 as r,I as c,i as h,g as U,$ as j,S as k}from"./index.9e912d9b.js";const q={class:"bookmark"},G=h("\u6DFB\u52A0\u7B56\u7565\u6A21\u677F"),H=h(" -> "),J=h(" \u4E0A\u4F20\u7B56\u7565\u6A21\u677F "),K=U("div",{class:"el-upload__tip text-red"}," \u4E00\u6B21\u53EA\u80FD\u4E0A\u4F20\u4E00\u4E2A\u6587\u4EF6 ",-1),L={key:0,style:{cursor:"pointer"}},O={key:0,style:{cursor:"pointer"}},Q={key:0,style:{cursor:"pointer"}},ee=T({setup(X){const p=$([]),d=R(),f=()=>{I().then(l=>{p.length=0,l.data.forEach((a,y)=>{p.push(a)})})},E=l=>{d.value.clearFiles();const a=l[0];a.uid=M(),d.value.handleStart(a)},v=()=>{d.value.submit(),f()},w=l=>{l.status=2,V(l.file_name).then(a=>{a.status==200&&(l.status=1),a.status==500&&(l.status=0)})},C=l=>{N(l.class_name).then(a=>{a.status==200&&(l.status=0),a.status==500&&(l.status=1)})},b=l=>{S(l.file_name).then(a=>{f()}).catch(a=>{j({message:k("p",null,[k("i",{style:"color: teal"},a)])})})};return f(),(l,a)=>{const y=i("InfoFilled"),B=i("SuccessFilled"),x=i("WarningFilled"),A=i("CirclePlusFilled"),D=i("RemoveFilled"),z=i("Delete");return n(),_("div",q,[e(t(P),{ref_key:"upload",ref:d,class:"upload-demo",action:"http://localhost:5000/trader/api/v1/strategy_file",limit:1,"on-exceed":E,"auto-upload":!1},{trigger:s(()=>[e(t(g),{type:"primary"},{default:s(()=>[G]),_:1})]),tip:s(()=>[K]),default:s(()=>[H,e(t(g),{class:"ml-3",type:"success",onClick:v},{default:s(()=>[J]),_:1})]),_:1},512),e(t(W),{ref:"multipleTableRef",data:t(p),style:{width:"100%"}},{default:s(()=>[e(t(u),{type:"selection",width:"55"}),e(t(u),{type:"index",label:"index",width:"80"}),e(t(u),{prop:"file_name",label:"\u7B56\u7565\u6587\u4EF6\u540D",width:"200"}),e(t(u),{prop:"class_name",label:"\u7B56\u7565\u7C7B\u540D",width:"200"}),e(t(u),{prop:"status",label:"\u72B6\u6001",width:"60"},{default:s(o=>[o.row.status==0?(n(),m(t(r),{key:0,size:20},{default:s(()=>[e(y)]),_:1})):c("",!0),o.row.status==1?(n(),m(t(r),{key:1,size:20,color:"green"},{default:s(()=>[e(B)]),_:1})):c("",!0),o.row.status==2?(n(),m(t(r),{key:2,size:20,color:"gold"},{default:s(()=>[e(x)]),_:1})):c("",!0)]),_:1}),e(t(u),{prop:"url",label:"\u52A0\u8F7D",width:"60"},{default:s(o=>[o.row.status==0?(n(),_("span",L,[e(t(r),{size:20,onClick:F=>w(o.row),color:"blue"},{default:s(()=>[e(A)]),_:2},1032,["onClick"])])):c("",!0)]),_:1}),e(t(u),{prop:"url",label:"\u5378\u8F7D",width:"60"},{default:s(o=>[o.row.status==1?(n(),_("span",O,[e(t(r),{size:20,onClick:F=>C(o.row),color:"red"},{default:s(()=>[e(D)]),_:2},1032,["onClick"])])):c("",!0)]),_:1}),e(t(u),{prop:"url",label:"\u5220\u9664",width:"60"},{default:s(o=>[o.row.status==0?(n(),_("span",Q,[e(t(r),{size:20,onClick:F=>b(o.row),color:"red"},{default:s(()=>[e(z)]),_:2},1032,["onClick"])])):c("",!0)]),_:1})]),_:1},8,["data"])])}}});export{ee as default};
|
|
||||||
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB |
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{a as o}from"./number.46c8fb59.js";const r=(e,t)=>(e.getMonth()+1,e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),Math.floor((e.getMonth()+3)/3),e.getMilliseconds(),/(y+)/.test(t)&&(t=t.replace(RegExp.$1,(e.getFullYear()+"").substr(4-RegExp.$1.length))),t),n=(e,t)=>(t||(t="yyyy-MM-dd hh:mm:ss"),r(new Date(e),t).toLocaleString()),l=e=>e.getFullYear()+"-"+o(e.getMonth()+1)+"-"+o(e.getDate());export{n as f,l as t};
|
|
||||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 410 KiB |
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{g as x,a as $,p as j,b as q}from"./blogView.38a54248.js";import{d as A,c as h,f as r,h as e,w as l,u as a,F as y,x as k,g as i,r as C,e as u,o as _,B as T,z as w,i as m}from"./index.9e912d9b.js";import"./index.26aa7e8a.js";const G=i("span",null,"\u5206\u7C7B\u641C\u7D22",-1),H=i("span",{class:"text-gray-500"},"-",-1),J=m("\u641C\u7D22"),K=m("\u521B\u4F5C"),M=m("\u5168\u90E8\u91CD\u65B0\u53D1\u5E03"),O={class:"blog_list"},P=["onClick"],Q={style:{display:"flex","justify-content":"space-between","align-items":"center"}},R={style:{"font-size":"12px",height:"16px","line-height":"16px",overflow:"hidden","text-overflow":"ellipsis"}},W=m("\u91CD\u65B0\u53D1\u5E03 "),X={class:"page_style"},oe=A({setup(Y){const s=h({key_word:"",btId:"",start_day:"",end_day:"",page_number:1,page_size:20,total:1}),p=h([]),b=h([]),B=()=>{x(s).then(n=>{p.splice(0,p.length),n.data.forEach(t=>{p.push(t)})})},v=n=>{const{href:t}=C.resolve({path:"/view",query:{bid:n}});window.open(t,"_blank")},V=()=>{const{href:n}=C.resolve({path:"/write/"});window.open(n,"_blank")},E=()=>{j()},F=n=>{q(n)};return x({}).then(n=>{n.data.forEach(t=>{p.push(t)})}),$().then(n=>{b.push({btId:"",btName:"\u9009\u62E9\u5206\u7C7B"}),n.data.forEach(t=>{const f={btId:t.btId,btName:t.btName};b.push(f)})}),(n,t)=>{const f=u("el-input"),d=u("el-col"),D=u("el-option"),N=u("el-select"),g=u("el-form-item"),I=u("el-date-picker"),z=u("el-time-picker"),c=u("el-button"),U=u("el-form"),L=u("el-pagination");return _(),r(y,null,[e(U,{model:a(s),"label-width":"120px"},{default:l(()=>[e(g,{label:"\u5173\u952E\u5B57\u641C\u7D22"},{default:l(()=>[e(d,{span:7},{default:l(()=>[e(f,{modelValue:a(s).key_word,"onUpdate:modelValue":t[0]||(t[0]=o=>a(s).key_word=o)},null,8,["modelValue"])]),_:1}),e(d,{span:1}),e(d,{span:10},{default:l(()=>[G,e(N,{modelValue:a(s).btId,"onUpdate:modelValue":t[1]||(t[1]=o=>a(s).btId=o),placeholder:"\u9009\u62E9\u5206\u7C7B"},{default:l(()=>[(_(!0),r(y,null,k(a(b),o=>(_(),T(D,{key:o.btId,label:o.btName,value:o.btId},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),_:1})]),_:1}),e(g,{label:"\u521B\u4F5C\u65F6\u95F4"},{default:l(()=>[e(d,{span:7},{default:l(()=>[e(I,{modelValue:a(s).start_day,"onUpdate:modelValue":t[2]||(t[2]=o=>a(s).start_day=o),type:"date",placeholder:"\u5F00\u59CB\u65F6\u95F4",style:{width:"100%"}},null,8,["modelValue"])]),_:1}),e(d,{span:2,class:"text-center"},{default:l(()=>[H]),_:1}),e(d,{span:7},{default:l(()=>[e(z,{modelValue:a(s).end_day,"onUpdate:modelValue":t[3]||(t[3]=o=>a(s).end_day=o),placeholder:"\u7ED3\u675F\u65F6\u95F4",style:{width:"100%"}},null,8,["modelValue"])]),_:1}),e(d,{span:6,style:{"text-align":"center"}},{default:l(()=>[e(c,{type:"primary",onClick:B},{default:l(()=>[J]),_:1})]),_:1})]),_:1})]),_:1},8,["model"]),e(c,{onClick:V},{default:l(()=>[K]),_:1}),e(c,{onClick:E},{default:l(()=>[M]),_:1}),(_(!0),r(y,null,k(a(p),o=>(_(),r("div",O,[i("h3",{style:{cursor:"pointer",width:"min-content","white-space":"nowrap"},onClick:S=>v(o.bid)},w(o.title),9,P),i("div",Q,[i("p",R,w(o.content),1),e(c,{size:"small",type:"success",onClick:S=>F(o.bid)},{default:l(()=>[W]),_:2},1032,["onClick"])])]))),256)),i("div",X,[e(L,{small:"",background:"",layout:"prev, pager, next",total:50,class:"mt-4"})])],64)}}});export{oe as default};
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-4
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{d as q,c as z,b as m,l as P,q as W,$ as p,S as o,f as C,g as D,h as e,w as n,u as d,F as B,e as s,o as b,x as A,B as E,Y as X,Z as G,W as H}from"./index.9e912d9b.js";import{s as J,g as K,a as O,c as Q}from"./strategy.e0f2bc38.js";import{t as T}from"./number.46c8fb59.js";const ee={class:"demo-collapse"},le={style:{cursor:"pointer"}},te=D("label",null," concel subscribe",-1),ue=q({setup(oe){const g=H(),_=J(),w=z([]),v=m(),y=m(),x=m(0),k=m(["1"]),f=m(""),I=()=>{!v.value||O(v.value).then(l=>{p({message:o("p",null,[o("i",{style:"color: green"},"\u884C\u60C5\u8BA2\u9605\u6210\u529F")])}),_.select_subscribe_vt_symbols(),h()}).catch(l=>{p({message:o("p",null,[o("i",{style:"color: red"},"\u884C\u60C5\u8BA2\u9605\u5931\u8D25")])})})},M=()=>{!f.value||Q(f.value).then(l=>{p({message:o("p",null,[o("i",{style:"color: green"},"\u53D6\u6D88\u8BA2\u9605\u6210\u529F")])}),h()}).catch(l=>{p({message:o("p",null,[o("i",{style:"color: red"},"\u53D6\u6D88\u8BA2\u9605\u5931\u8D25")])})})},S=(l,t)=>{let a=(l.last_price-l.open_price)/l.open_price;return T(a)},N=(l,t,a,i)=>{f.value=l.symbol+"."+l.exchange,console.log(f.value)},U=(l,t,a,i)=>{},L=(l,t,a)=>{var r;let i=(r=g==null?void 0:g.proxy)==null?void 0:r.$refs.contextmenu;a.preventDefault(),i.show({top:a.clientY,left:a.clientX}),window.onclick=()=>{i.hide()}},h=()=>(K().then(l=>{w.length=0,l.data.ticks.forEach(t=>{w.push(t)})}),h);return P(()=>{clearInterval(x.value),x.value=window.setInterval(h(),3e3)}),W(()=>{window.clearInterval(x.value)}),_.select_subscribe_vt_symbols().catch(l=>{p({message:o("p",null,[o("i",{style:"color: teal"},"\u8BFB\u53D6vt_symbols\u5931\u8D25")])})}),_.select_vt_symbols().catch(l=>{p({message:o("p",null,[o("i",{style:"color: teal"},"\u8BFB\u53D6vt_symbols\u5931\u8D25")])})}),_.select_exchanges().catch(l=>{p({message:o("p",null,[o("i",{style:"color: teal"},"\u8BFB\u53D6exchanges\u5931\u8D25")])})}),(l,t)=>{const a=s("el-option"),i=s("el-select"),r=s("el-col"),R=s("ZoomIn"),V=s("el-icon"),Z=s("el-row"),F=s("el-collapse-item"),u=s("el-table-column"),$=s("el-table"),Y=s("el-collapse"),j=s("CircleClose");return b(),C(B,null,[D("div",ee,[e(Y,{modelValue:k.value,"onUpdate:modelValue":t[3]||(t[3]=c=>k.value=c)},{default:n(()=>[e(F,{title:"\u8BA2\u9605\u884C\u60C5",name:"2"},{default:n(()=>[e(Z,null,{default:n(()=>[e(r,{span:4},{default:n(()=>[e(i,{modelValue:y.value,"onUpdate:modelValue":t[0]||(t[0]=c=>y.value=c),placeholder:"select a exchange"},{default:n(()=>[(b(!0),C(B,null,A(d(_).strategy.exchanges,c=>(b(),E(a,{value:c},null,8,["value"]))),256))]),_:1},8,["modelValue"])]),_:1}),e(r,{span:1}),e(r,{span:4},{default:n(()=>[e(i,{modelValue:v.value,"onUpdate:modelValue":t[1]||(t[1]=c=>v.value=c),placeholder:"select a vt_symbol"},{default:n(()=>[(b(!0),C(B,null,A(d(_).strategy.vt_symbols.get(y.value),c=>(b(),E(a,{value:c},null,8,["value"]))),256))]),_:1},8,["modelValue"])]),_:1}),e(r,{span:1}),e(r,{span:4},{default:n(()=>[D("span",le,[e(V,{size:25,onClick:t[2]||(t[2]=c=>I())},{default:n(()=>[e(R)]),_:1})])]),_:1})]),_:1})]),_:1}),e(F,{title:"\u8BA2\u9605\u4E00\u89C8",name:"1"},{default:n(()=>[e($,{onRowContextmenu:L,onCellMouseEnter:N,onCellMouseLeave:U,data:d(w),style:{width:"100%"}},{default:n(()=>[e(u,{fixed:"",prop:"symbol",label:"symbol",width:"80"}),e(u,{prop:"exchange",label:"exchange",width:"100"}),e(u,{prop:"name",label:"Name",width:"120"}),e(u,{prop:"last_price",label:"last_price",width:"120"}),e(u,{prop:"volume",label:"volume",width:"100"}),e(u,{prop:"open_price",label:"open_price",width:"120"}),e(u,{prop:"high_price",label:"high_price",width:"120"}),e(u,{prop:"low_price",label:"low_price",width:"100"}),e(u,{prop:"differ",label:"differ",width:"70"}),e(u,{prop:"differ_percent",label:"differ_per",formatter:S,width:"120"})]),_:1},8,["data"])]),_:1})]),_:1},8,["modelValue"])]),e(d(G),{"auto-ajust-placement":"",ref:"contextmenu"},{default:n(()=>[e(d(X),{onClick:M},{default:n(()=>[e(V,{class:"contextmenu-icon"},{default:n(()=>[e(j)]),_:1}),te]),_:1})]),_:1},512)],64)}}});export{ue as default};
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.category_card-box[data-v-2dc81d35]{display:flex;flex-wrap:wrap}.category_card__header[data-v-2dc81d35]{text-align:center;width:100px;line-height:100px;height:100px}.category_card__body[data-v-2dc81d35]{text-align:center}.onenote_card__header[data-v-2dc81d35]{width:120px}.onenote_card-box[data-v-2dc81d35]{display:flex;flex-direction:column}.onenote_item_card[data-v-2dc81d35]{display:flex;margin:10px}.onenote_category_card[data-v-2dc81d35]{display:flex;flex-direction:column;margin:20px;padding:20px}.category_icon[data-v-2dc81d35]{margin-bottom:50px}.category_theme[data-v-2dc81d35]{margin-right:30px}
|
|
||||||
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.blog_list{display:flex;flex-direction:column;border-bottom:1px solid rgba(151,151,151,.3);padding-top:10px;padding-bottom:10px}.page_style{margin-top:25px;display:flex;flex-direction:column;align-items:center}
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:transparent!important}
|
|
||||||
Vendored
-61
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{v as q,D as T,_ as J,d as K,c as g,b as p,l as Q,f as u,H as X,B as Y,w as a,I as L,h as l,u as o,F as S,e as n,G as Z,o as i,g as c,z as r,x as ee,i as E,p as te,j as le,m as oe}from"./index.9e912d9b.js";import{t as f}from"./date.86e91942.js";import{s as ae}from"./settings.89e47c65.js";import"./number.46c8fb59.js";const ne=q.create(),se=()=>ne({url:"https://holidays-jp.github.io/api/v1/2023/date.json",method:"GET"}),de={"Content-Type":"application/json;charsetset=UTF-8"},ie=_=>T({url:"/calendar/api/v1/event",method:"PUT",data:_}),ue=()=>T({url:"/calendar/api/v1/event",method:"GET",headers:de});const U=_=>(te("data-v-0e3dfbc2"),_=_(),le(),_),re={key:0,class:"date-cell-holiday"},ce=["onClick"],_e=U(()=>c("br",null,null,-1)),me={key:1,class:"date-cell"},pe=["onClick"],fe=["onClick"],ve={key:2,class:"date-cell-event"},he=U(()=>c("span",null,"\u5F85\u529E\u4E8B\u9879",-1)),be={class:"dialog-footer"},ge=E("Cancel"),ke=E(" Confirm "),ye=K({setup(_){const v=ae(),k=g({}),y=g([]),x=g({}),d=g({reminder_date:"",title:"",reminder_info:""}),D=p(new Date),m=p(!1),h="140px",w=p(!1),B=p(!0),F=p([]),$=["email","messageBox","\u624B\u673A\u77ED\u4FE1","\u5FAE\u4FE1\u901A\u77E5"],C=s=>{d.reminder_date=f(s),m.value=!0},N=async()=>{await ie(d).then(()=>{}),m.value=!1,O("refresh")},O=s=>{s==="refresh"&&(v.settings.isLoading=!0,v.settings.isRouterAlive=!1,oe(()=>{v.settings.isRouterAlive=!0,v.settings.isLoading=!1}))};return Q(async()=>{await se().then(s=>{Object.keys(s.data).forEach(t=>{k[t]=s.data[t]})}),await ue().then(s=>{y.length=0,s.data.forEach(t=>{y.push(t),x[t.reminder_date]=t.title})}),w.value=!0,B.value=!1}),(s,t)=>{const G=n("el-calendar"),V=n("el-table-column"),R=n("el-table"),b=n("el-form-item"),A=n("el-input"),z=n("el-checkbox"),H=n("el-checkbox-group"),M=n("el-form"),j=n("el-button"),P=n("el-dialog"),W=Z("loading");return i(),u(S,null,[w.value?X((i(),Y(G,{key:0,modelValue:D.value,"onUpdate:modelValue":t[0]||(t[0]=e=>D.value=e),"element-loading-text":"\u4E3B\u4EBA\uFF0C\u522B\u7740\u6025\u6211\u5728\u52AA\u529B\u52A0\u8F7D\u4E2D^_^"},{dateCell:a(({data:e})=>[Object.keys(o(k)).includes(o(f)(e.date))?(i(),u("div",re,[c("span",{style:{color:"red"},onClick:I=>C(e.date)},r(e.date.getDate()),9,ce),_e,c("span",null,r(o(k)[o(f)(e.date)]),1)])):(i(),u("div",me,[e.date.getDay()==0||e.date.getDay()==6?(i(),u("span",{key:0,style:{color:"red"},onClick:I=>C(e.date)},r(e.date.getDate()),9,pe)):(i(),u("span",{key:1,onClick:I=>C(e.date)},r(e.date.getDate()),9,fe))])),Object.keys(o(x)).includes(o(f)(e.date))?(i(),u("div",ve,[c("span",null,r(o(x)[o(f)(e.date)]),1)])):L("",!0)]),_:1},8,["modelValue"])),[[W,B.value]]):L("",!0),he,l(R,{data:o(y)},{default:a(()=>[l(V,{property:"reminder_date",label:"Date",width:"150"}),l(V,{property:"title",label:"title",width:"200"}),l(V,{property:"reminder_info",label:"eventInfo"})]),_:1},8,["data"]),l(P,{modelValue:m.value,"onUpdate:modelValue":t[5]||(t[5]=e=>m.value=e),title:"\u5F85\u529E\u4E8B\u9879"},{footer:a(()=>[c("span",be,[l(j,{onClick:t[4]||(t[4]=e=>m.value=!1)},{default:a(()=>[ge]),_:1}),l(j,{type:"primary",onClick:N},{default:a(()=>[ke]),_:1})])]),default:a(()=>[l(M,{model:o(d)},{default:a(()=>[l(b,{label:"\u65E5\u671F","label-width":h},{default:a(()=>[c("span",null,r(o(d).reminder_date),1)]),_:1}),l(b,{label:"title","label-width":h},{default:a(()=>[l(A,{modelValue:o(d).title,"onUpdate:modelValue":t[1]||(t[1]=e=>o(d).title=e),autocomplete:"off"},null,8,["modelValue"])]),_:1}),l(b,{label:"eventInfo","label-width":h},{default:a(()=>[l(A,{modelValue:o(d).reminder_info,"onUpdate:modelValue":t[2]||(t[2]=e=>o(d).reminder_info=e),autocomplete:"off",type:"textarea"},null,8,["modelValue"])]),_:1}),l(b,{label:"alert","label-width":h},{default:a(()=>[l(H,{modelValue:F.value,"onUpdate:modelValue":t[3]||(t[3]=e=>F.value=e),min:0,max:2},{default:a(()=>[(i(),u(S,null,ee($,e=>l(z,{key:e,label:e},{default:a(()=>[E(r(e),1)]),_:2},1032,["label"])),64))]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue"])],64)}}});var De=J(ye,[["__scopeId","data-v-0e3dfbc2"]]);export{De as default};
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{_ as e,f as o,o as _}from"./index.9e912d9b.js";const a={},n={class:"dialog-footer"};function r(c,s){return _(),o("span",n," \u5F53\u4F60\u770B\u5230\u4E86\uFF0C\u8FD9\u4E2A\u9875\u9762\uFF0C\u8FD9\u8868\u793A\u4E86\uFF0C\u4F60\u901A\u8FC7\u767E\u5EA6\u626B\u63CF\u767B\u9646\u4E86\u6211\u7684\u79D8\u5BC6\u57FA\u5730\uFF0C\u4F46\u662F\u5F88\u9057\u61BE\u7684\u544A\u8BC9\u4F60\uFF0C\u6211\u4EEC\u5C06\u4EE5\u975E\u6CD5\u767B\u5F55\u7684\u65B9\u5F0F\u5904\u7406\u4F60\u7684\u8BF7\u6C42\uFF0C88 ")}var d=e(a,[["render",r]]);export{d as default};
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{d as s,B as a,w as n,a5 as c,$ as l,e as i,o as r,i as p}from"./index.9e912d9b.js";const _=p("Click to open the Message Box"),f=s({setup(m){const t=()=>{c.alert("This is a message","Title",{confirmButtonText:"OK",callback:e=>{l({type:"info",message:`action: ${e}`})}})};return(e,u)=>{const o=i("el-button");return r(),a(o,{text:"",onClick:t},{default:n(()=>[_]),_:1})}}});export{f as default};
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.dashboard{background-color:beige}.iconStyle{margin-right:"6px"}.operate,.descriptionsclass{display:flex;align-items:center}
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.dashboard-line-box .dashboard-line[data-v-19c5604b]{background-color:#fff;height:360px;width:100%}.dashboard-line-box .dashboard-line-title[data-v-19c5604b]{font-weight:600;margin-bottom:12px}.commit-table[data-v-554f7f6a]{background-color:#fff;height:400px}.commit-table-title[data-v-554f7f6a]{font-weight:600;margin-bottom:12px}.commit-table .log-item[data-v-554f7f6a]{display:flex;justify-content:space-between;margin-top:14px}.commit-table .log-item .key-box[data-v-554f7f6a]{justify-content:center}.commit-table .log-item .key[data-v-554f7f6a]{display:inline-flex;justify-content:center;align-items:center;width:20px;height:20px;border-radius:50%;background:#F0F2F5;text-align:center;color:#000000a6}.commit-table .log-item .key.top[data-v-554f7f6a]{background:#314659;color:#fff}.commit-table .log-item .message[data-v-554f7f6a]{color:#000000a6}.commit-table .log-item .form[data-v-554f7f6a]{color:#000000a6;margin-left:12px}.commit-table .log-item .flex[data-v-554f7f6a]{line-height:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.commit-table .log-item .flex-1[data-v-554f7f6a]{flex:1}.commit-table .log-item .flex-2[data-v-554f7f6a]{flex:2}.commit-table .log-item .flex-3[data-v-554f7f6a]{flex:3}.commit-table .log-item .flex-4[data-v-554f7f6a]{flex:4}.commit-table .log-item .flex-5[data-v-554f7f6a]{flex:5}.page[data-v-cb159114]{background:#f0f2f5;padding:0}.page .gva-card-box[data-v-cb159114]{padding:12px 16px}.page .gva-card-box+.gva-card-box[data-v-cb159114]{padding-top:0}.page .gva-card[data-v-cb159114]{box-sizing:border-box;background-color:#fff;border-radius:2px;height:auto;padding:26px 30px;overflow:hidden;box-shadow:0 0 7px 1px #00000008}.page .gva-top-card[data-v-cb159114]{height:260px;display:flex;align-items:center;justify-content:space-between;color:#777}.page .gva-top-card-left[data-v-cb159114]{height:100%;display:flex;flex-direction:column}.page .gva-top-card-left-title[data-v-cb159114]{font-size:22px;color:#343844}.page .gva-top-card-left-dot[data-v-cb159114]{font-size:16px;color:#6b7687;margin-top:24px}.page .gva-top-card-left-rows[data-v-cb159114]{margin-top:18px;color:#6b7687;width:600px;align-items:center}.page .gva-top-card-left-item[data-v-cb159114]{margin-top:14px}.page .gva-top-card-left-item+.gva-top-card-left-item[data-v-cb159114]{margin-top:24px}.page .gva-top-card-right[data-v-cb159114]{height:600px;width:600px;margin-top:28px}.page[data-v-cb159114] .el-card__header{padding:0;border-bottom:none}.page .card-header[data-v-cb159114]{padding-bottom:20px;border-bottom:1px solid #e8e8e8}.page .quick-entrance-title[data-v-cb159114]{height:30px;font-size:22px;color:#333;width:100%;border-bottom:1px solid #eee}.page .quick-entrance-items[data-v-cb159114]{display:flex;align-items:center;justify-content:center;text-align:center;color:#333}.page .quick-entrance-items .quick-entrance-item[data-v-cb159114]{padding:16px 28px;margin-top:-16px;margin-bottom:-16px;border-radius:4px;transition:all .2s;cursor:pointer;height:auto;text-align:center}.page .quick-entrance-items .quick-entrance-item[data-v-cb159114]:hover{box-shadow:0 0 7px #d9d9d98c}.page .quick-entrance-items .quick-entrance-item-icon[data-v-cb159114]{width:50px;height:50px!important;border-radius:8px;display:flex;align-items:center;justify-content:center;margin:0 auto}.page .quick-entrance-items .quick-entrance-item-icon i[data-v-cb159114]{font-size:24px}.page .quick-entrance-items .quick-entrance-item p[data-v-cb159114]{margin-top:10px}.page .echart-box[data-v-cb159114]{padding:14px}.dashboard-icon[data-v-cb159114]{font-size:20px;color:#55a0f8;width:30px;height:30px;margin-right:10px;display:flex;align-items:center}.flex-center[data-v-cb159114]{display:flex;align-items:center}@media (max-width: 750px){.gva-card[data-v-cb159114]{padding:20px 10px!important}.gva-card .gva-top-card[data-v-cb159114]{height:auto}.gva-card .gva-top-card-left-title[data-v-cb159114]{font-size:20px!important}.gva-card .gva-top-card-left-rows[data-v-cb159114]{margin-top:15px;align-items:center}.gva-card .gva-top-card-right[data-v-cb159114]{display:none}.gva-card .gva-middle-card-item[data-v-cb159114]{line-height:20px}.gva-card .dashboard-icon[data-v-cb159114]{font-size:18px}}
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{D as M,d as V,c as b,b as f,f as z,h as l,w as a,u as r,V as L,F as N,W as j,X as g,e as y,o as i,B as p,Y as m,I as h,Z as O,g as k}from"./index.9e912d9b.js";const U={"Content-Type":"application/json;charsetset=UTF-8"},X=w=>M({url:"/cloud/api/v1/file/list",method:"GET",params:{url:w},headers:U});const Y=k("label",null," _new folder",-1),$=k("label",null," _copy",-1),A=k("label",null," _rename",-1),G=k("label",null," _delete",-1),I=k("label",null," _delete",-1),Z=V({setup(w){const u=j(),R=b([]),n=b(new Set),C=b({isCtrl:!1,isShift:!1}),E=f(),x=f(),d=f(!0);f();const v=f(!1),F=(e,o,t,s)=>{n.has(e)||(x.value=e)},B=(e,o,t,s)=>{n.has(e)||(x.value=void 0)},D=(e,o,t)=>{C.isCtrl?n.has(e)?n.delete(e):n.add(e):(n.clear(),n.add(e))},S=(e,o,t)=>{var c;v.value=!0;let s=(c=u==null?void 0:u.proxy)==null?void 0:c.$refs.contextmenu;n.has(e)||(n.clear(),n.add(e)),t.preventDefault(),s.show({top:t.clientY,left:t.clientX}),window.onclick=()=>{s.hide(),v.value=!1}},_=()=>{},T=({row:e,rowIndex:o})=>{var t;if(n.has(e))return{background:"#B4C7E7"};if(((t=g(x.value))==null?void 0:t.name)==g(e).name)return{background:"#DAE3F3"}};return document.onkeydown=e=>{switch(e.key){case"Control":C.isCtrl=!0;break}},document.onkeyup=e=>{var o;switch(e.key){case"Control":C.isCtrl=!1;break;case"Escape":v.value?(((o=u==null?void 0:u.proxy)==null?void 0:o.$refs.contextmenu).hide(),v.value=!1):n.clear(),C.isCtrl=!0;break}},X("").then(e=>{e.data.forEach(o=>{const t={size:o.size,isDir:o.isDir,name:o.server_filename,path:o.path};R.push(t)})}),(e,o)=>{const t=y("el-table-column"),s=y("FolderOpened"),c=y("el-icon");return i(),z(N,null,[l(r(L),{data:r(R),onCellMouseEnter:F,onCellMouseLeave:B,"row-style":T,onRowContextmenu:S,onRowClick:D,ref_key:"multipleTableRef",ref:E},{default:a(()=>[l(t,{prop:"name",width:"200px"}),l(t,{prop:"isDir",width:"130px"}),l(t,{prop:"size",width:"130px"}),l(t,{prop:"path",width:"130px"})]),_:1},8,["data"]),l(r(O),{"auto-ajust-placement":"",ref:"contextmenu"},{default:a(()=>[d.value?(i(),p(r(m),{key:0,onClick:_},{default:a(()=>[l(c,{class:"contextmenu-icon"},{default:a(()=>[l(s)]),_:1}),Y]),_:1})):h("",!0),d.value?(i(),p(r(m),{key:1,onClick:_},{default:a(()=>[l(c,{class:"contextmenu-icon"},{default:a(()=>[l(s)]),_:1}),$]),_:1})):h("",!0),d.value?(i(),p(r(m),{key:2,onClick:_},{default:a(()=>[l(c,{class:"contextmenu-icon"},{default:a(()=>[l(s)]),_:1}),A]),_:1})):h("",!0),d.value?(i(),p(r(m),{key:3,onClick:_},{default:a(()=>[l(c,{class:"contextmenu-icon"},{default:a(()=>[l(s)]),_:1}),G]),_:1})):h("",!0),d.value?(i(),p(r(m),{key:4,onClick:_},{default:a(()=>[l(c,{class:"contextmenu-icon"},{default:a(()=>[l(s)]),_:1}),I]),_:1})):h("",!0)]),_:1},512)],64)}}});export{Z as default};
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-60
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.date-cell-holiday[data-v-0e3dfbc2]{background:#dfd}.date-cell-event[data-v-0e3dfbc2]{background:yellow}
|
|
||||||
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.el-button--text[data-v-84f682ae]{margin-right:15px}.el-select[data-v-84f682ae],.el-input[data-v-84f682ae]{width:300px}.dialog-footer button[data-v-84f682ae]:first-child{margin-right:10px}.el-button--text[data-v-25eee70b]{margin-right:15px}.el-select[data-v-25eee70b],.el-input[data-v-25eee70b]{width:300px}.dialog-footer button[data-v-25eee70b]:first-child{margin-right:10px}.dashboard{background-color:beige}.tag_list[data-v-85509c2e]{display:flex;border-top:1px solid rgba(151,151,151,.3);border-bottom:1px solid rgba(151,151,151,.3)}.click-icon[data-v-85509c2e]{width:40px;margin:10px;cursor:pointer}.create_dialog[data-v-85509c2e]{margin:10px}
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.dashboard{background-color:beige}
|
|
||||||
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.section-main{height:100%;padding:14px}.headerAvatar[data-v-db52df48]{display:flex;justify-content:center;align-items:center;margin-right:8px}.file[data-v-db52df48]{width:80px;height:80px;position:relative}.right-box[data-v-47d8c705]{padding-top:16px;display:flex;justify-content:flex-end;align-items:center}.right-box img[data-v-47d8c705]{vertical-align:middle;border:1px solid #ccc;border-radius:6px}.item[data-v-47d8c705]{margin-top:5px;margin-right:30px}.header-avatar[data-v-47d8c705]{display:flex;justify-content:center;align-items:center}.side_Style[data-v-52f0823c]{width:100px}.side-main[data-v-52f0823c]{width:200px}.gva-menu-item[data-v-52f0823c]{color:#fff}.el-menu-item.is-active[data-v-52f0823c]{color:var(--ddab178a);background:var(--ddab178a)}.el-header[data-v-4dcee88b]{border-bottom-style:solid;border-bottom-width:.5px;border-bottom-color:#9797974d}.el-main[data-v-4dcee88b]{padding:16px;overflow:hidden;height:100%}.el-aside[data-v-4dcee88b]{margin-left:-10px;background:#191a23;position:fixed}.el-footer[data-v-4dcee88b]{margin-top:20px;display:flex;justify-content:space-around}.homeWrap[data-v-4dcee88b]{position:absolute;top:0;height:100%;width:100%}
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
.text[data-v-6c04fabb]{font-size:14px}.item[data-v-6c04fabb]{padding:18px 0}.yuliu[data-v-6c04fabb]{height:600px;float:left;background:url(/assets/have_a_nice_day.4bde267a.jpeg) center top no-repeat;background-size:cover}
|
|
||||||
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{E as u}from"./style.2622ccfc.js";import{d as i,b as s,f as m,g as d,z as p,u as a,h as c,P as f,F as g,a6 as V,o as B}from"./index.9e912d9b.js";import{c as _}from"./blogView.38a54248.js";import"./index.26aa7e8a.js";const F=i({setup(v){let e=s(""),o=s("");const n=V().query;return(()=>{_(n.bid).then(t=>{e.value=t.data.content,o.value=t.data.title})})(),(t,l)=>(B(),m(g,null,[d("h2",null,p(a(o)),1),c(a(u),{modelValue:a(e),"onUpdate:modelValue":l[0]||(l[0]=r=>f(e)?e.value=r:e=r),previewOnly:""},null,8,["modelValue"])],64))}});export{F as default};
|
|
||||||
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
const r=t=>(t*100).toFixed(2)+"%",e=t=>t>10?t:"0"+t;export{e as a,r as t};
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{d as f,c as b,f as V,h as e,w as l,u as o,F as C,i as m,g as B,a6 as E,e as r,o as F,bW as k,s as h,a as A,r as g}from"./index.9e912d9b.js";const w=m(" \u8A72\u5F53\u30B7\u30B9\u30C6\u30E0\u306E\u3054\u5229\u7528\u306F\u30B7\u30B9\u30C6\u30E0\u7BA1\u7406\u8005\u306B\u8A31\u53EF\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002"),x=B("br",null,null,-1),U=m(" \u8A31\u53EF\u304C\u306A\u3051\u308C\u3070\u3001\u30E6\u30FC\u30B6\u30FC\u60C5\u5831\u3092\u767B\u9332\u3057\u3066\u3082\u3001\u30B7\u30B9\u30C6\u30E0\u306E\u3054\u5229\u7528\u306F\u3067\u304D\u307E\u305B\u3093\u306E\u3067\u3001\u3054\u6CE8\u610F\u304F\u3060\u3055\u3044\u3002 "),v=m("Register"),y=m("Cancel"),R=f({setup(I){const d=E().query,u=b({phone_number:"",code:"",tenant_id:d.tenantId,account:d.account,token:d.token}),i=()=>{k(u).then(_=>{if(_.status==200){const t={id:d.tenantId,account:d.account};h(d.token),A(t);const{href:a}=g.resolve({path:"/"});window.open(a,"_self")}})};return(_,t)=>{const a=r("el-input"),s=r("el-form-item"),c=r("el-button"),p=r("el-form");return F(),V(C,null,[w,x,U,e(p,{model:o(u),"label-width":"120px"},{default:l(()=>[e(s,{label:"phone_number"},{default:l(()=>[e(a,{modelValue:o(u).phone_number,"onUpdate:modelValue":t[0]||(t[0]=n=>o(u).phone_number=n)},null,8,["modelValue"])]),_:1}),e(s,{label:"auth_code"},{default:l(()=>[e(a,{modelValue:o(u).code,"onUpdate:modelValue":t[1]||(t[1]=n=>o(u).code=n)},null,8,["modelValue"])]),_:1}),e(s,{label:"tenantId"},{default:l(()=>[e(a,{modelValue:o(u).tenant_id,"onUpdate:modelValue":t[2]||(t[2]=n=>o(u).tenant_id=n),disabled:!0},null,8,["modelValue"])]),_:1}),e(s,{label:"account"},{default:l(()=>[e(a,{modelValue:o(u).account,"onUpdate:modelValue":t[3]||(t[3]=n=>o(u).account=n),disabled:!0},null,8,["modelValue"])]),_:1}),e(s,{label:"token"},{default:l(()=>[e(a,{modelValue:o(u).token,"onUpdate:modelValue":t[4]||(t[4]=n=>o(u).token=n),disabled:!0},null,8,["modelValue"])]),_:1}),e(s,null,{default:l(()=>[e(c,{type:"primary",onClick:i},{default:l(()=>[v]),_:1}),e(c,null,{default:l(()=>[y]),_:1})]),_:1})]),_:1},8,["model"])],64)}}});export{R as default};
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{O as n,b as l,J as s}from"./index.9e912d9b.js";const d=n("settings",()=>{const e=l({sideMode:"#191a23",isMobile:!1,isRouterAlive:!0,isLoading:!1}),i=s(()=>e.value.sideMode),o=s(()=>e.value.isMobile),t=s(()=>e.value.isRouterAlive),a=s(()=>e.value.isLoading);return{settings:e,sideMode:i,isMobile:o,isRouterAlive:t,isLoading:a}});export{d as s};
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{_ as e,f as r,o as c}from"./index.9e912d9b.js";const o={},s={class:"yuliu"};function t(_,a){return c(),r("div",s," \u8FD9\u4E2A\u4EBA\u5F88\u61D2\uFF0C\u4EC0\u4E48\u4E5F\u6CA1\u5199 ")}var f=e(o,[["render",t]]);export{f as default};
|
|
||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
import{D as e,O as c,c as a}from"./index.9e912d9b.js";const v=()=>e({url:"/trader/api/v1/accounts",method:"GET"}),d=s=>e({url:"/trader/api/v1/tick/"+s,method:"GET"}),y=()=>e({url:"/trader/api/v1/ticks",method:"GET"}),h=s=>e({url:"/trader/api/v1/order",method:"POST",data:s}),g=s=>e({url:"/trader/api/v1/subscribe/"+s,method:"GET"}),o=()=>e({url:"/trader/api/v1/subscribe/vt_symbols",method:"GET"}),p=s=>e({url:"/trader/api/v1/subscribe/"+s,method:"DELETE"}),n=()=>e({url:"/trader/api/v1/vt_symbols",method:"GET"}),b=()=>e({url:"/trader/api/v1/exchanges",method:"GET"}),E=c("strategy",()=>{const s=a({class_names:[],vt_symbols:new Map,subscribe_vt_symbols:[],exchanges:[]});return{strategy:s,select_exchanges:async()=>{s.exchanges.length==0&&b().then(t=>{s.exchanges=t.data.exchanges})},select_vt_symbols:async()=>{s.vt_symbols.size==0&&n().then(t=>{Object.keys(t.data.vt_symbols).forEach(r=>{s.vt_symbols.set(r,t.data.vt_symbols[r])})})},select_subscribe_vt_symbols:async()=>{s.subscribe_vt_symbols.length==0&&o().then(t=>{s.subscribe_vt_symbols=t.data.subscribe_vt_symbols})}}});export{g as a,v as b,p as c,d,h as e,y as g,E as s};
|
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
-84
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 189 KiB |
Vendored
-18
@@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>violin-home</title>
|
|
||||||
<script type="module" crossorigin src="/assets/index.9e912d9b.js"></script>
|
|
||||||
<link rel="stylesheet" href="/assets/index.35a0e576.css">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>violin-home</title>
|
<title>个人知识记录</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';
|
|
||||||
import tenant from './tenant';
|
|
||||||
|
|
||||||
export function setupMock() {
|
|
||||||
createProdMockServer([...tenant]);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { MockMethod } from 'vite-plugin-mock'
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
url: '/traderCalender/api/v1/trader/calender/year/2024',
|
||||||
|
method: 'get',
|
||||||
|
response: ({ body, query }) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
month: 4,
|
||||||
|
month_beginning_balance: 132947.59,
|
||||||
|
offset_gain_and_loss: 0,
|
||||||
|
mark_to_market: 5300,
|
||||||
|
commission: 0,
|
||||||
|
deposit_and_withdrawal: 0,
|
||||||
|
month_end_balance: 138247.59,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
month: 5,
|
||||||
|
month_beginning_balance: 138247.59,
|
||||||
|
offset_gain_and_loss: 5080,
|
||||||
|
mark_to_market: 1960,
|
||||||
|
commission: 108,
|
||||||
|
deposit_and_withdrawal: 10000,
|
||||||
|
month_end_balance: 135179.59,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
month: 6,
|
||||||
|
month_beginning_balance: 135179.59,
|
||||||
|
offset_gain_and_loss: -2830,
|
||||||
|
mark_to_market: -2920,
|
||||||
|
commission: 32,
|
||||||
|
deposit_and_withdrawal: 10000,
|
||||||
|
month_end_balance: 119397.59,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
month: 7,
|
||||||
|
month_beginning_balance: 119397.59,
|
||||||
|
offset_gain_and_loss: 0,
|
||||||
|
mark_to_market: -5640,
|
||||||
|
commission: 16,
|
||||||
|
deposit_and_withdrawal: 0,
|
||||||
|
month_end_balance: 113741.59,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
month: 8,
|
||||||
|
month_beginning_balance: 113741.59,
|
||||||
|
offset_gain_and_loss: -2480,
|
||||||
|
mark_to_market: -4150,
|
||||||
|
commission: 24,
|
||||||
|
deposit_and_withdrawal: 1000,
|
||||||
|
month_end_balance: 106087.59,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
] as MockMethod[]
|
||||||
@@ -14,6 +14,11 @@ server {
|
|||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /profile {
|
||||||
|
alias /usr/share/nginx/html;
|
||||||
|
index index.html index.htm;
|
||||||
|
}
|
||||||
|
|
||||||
location /home {
|
location /home {
|
||||||
alias /usr/share/nginx/html;
|
alias /usr/share/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
|
|||||||
Generated
+4069
-3125
File diff suppressed because it is too large
Load Diff
+27
-37
@@ -1,54 +1,44 @@
|
|||||||
{
|
{
|
||||||
"name": "violin-home",
|
"name": "violin-home",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
"development": "vite build --mode development",
|
"build:test": "vue-tsc --noEmit && vite build --mode test",
|
||||||
"test": "vite --mode test",
|
"build:dev": "vue-tsc --noEmit && vite build --mode development",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^1.1.4",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@types/node": "^17.0.23",
|
"axios": "^1.7.7",
|
||||||
"aplayer": "^1.10.1",
|
"clipboard": "^2.0.11",
|
||||||
"axios": "^0.26.1",
|
"copy-to-clipboard": "^3.3.3",
|
||||||
"clipboard": "^2.0.10",
|
"dayjs": "^1.11.13",
|
||||||
"copy-to-clipboard": "^3.3.1",
|
"echarts": "^5.5.1",
|
||||||
"echarts": "^5.3.2",
|
"element-plus": "^2.14.1",
|
||||||
"element-plus": "^2.1.7",
|
"js-cookie": "^3.0.5",
|
||||||
"js-cookie": "^3.0.1",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lodash-unified": "^1.0.2",
|
"md-editor-v3": "^4.20.1",
|
||||||
"md-editor-v3": "^1.11.6",
|
"pinia": "^2.2.4",
|
||||||
"moment": "^2.29.4",
|
"qs": "^6.13.0",
|
||||||
"node-sass": "^8.0.0",
|
"v-contextmenu": "^3.2.0",
|
||||||
"pinia": "^2.0.13",
|
"vue": "^3.5.12",
|
||||||
"qs": "^6.10.3",
|
"vue-router": "^4.4.5",
|
||||||
"sass": "^1.57.1",
|
|
||||||
"sass-loader": "^13.2.0",
|
|
||||||
"save": "^2.4.0",
|
|
||||||
"scss": "^0.2.4",
|
|
||||||
"style-loader": "^3.3.1",
|
|
||||||
"type-fest": "^2.12.2",
|
|
||||||
"vue": "^3.2.25",
|
|
||||||
"vue-router": "^4.0.14",
|
|
||||||
"vue-runtime-helpers": "^1.1.2",
|
|
||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/js-cookie": "^3.0.1",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/qs": "^6.9.7",
|
"@types/node": "^22.7.5",
|
||||||
"@vitejs/plugin-vue": "^2.3.0",
|
"@types/qs": "^6.9.15",
|
||||||
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"typescript": "^4.5.4",
|
"sass": "^1.79.4",
|
||||||
"v-contextmenu": "^3.0.0",
|
"typescript": "~5.6.2",
|
||||||
"vite": "^2.9.13",
|
"vite": "^5.4.8",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-mock": "^2.9.6",
|
"vite-plugin-mock": "^3.0.2",
|
||||||
"vue-tsc": "^0.29.8"
|
"vue-tsc": "^2.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-12
@@ -1,26 +1,50 @@
|
|||||||
import { service } from '../utils/request'
|
import { service } from '../utils/request'
|
||||||
|
|
||||||
const headers = {
|
/**
|
||||||
'Content-Type': 'application/json;charsetset=UTF-8'
|
* 日历事件 API
|
||||||
}
|
* 对应后端 CalendarController: /api/v1/events
|
||||||
|
*/
|
||||||
const put_event = (data: Object) => {
|
const post_event = (data: {
|
||||||
|
eventDate: string
|
||||||
|
title: string
|
||||||
|
eventInfo?: string
|
||||||
|
}) => {
|
||||||
return service({
|
return service({
|
||||||
url: '/calendar/api/v1/event',
|
url: '/calendar/api/v1/events',
|
||||||
method: 'PUT',
|
method: 'POST',
|
||||||
data: data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const get_event = () => {
|
const get_event = () => {
|
||||||
return service({
|
return service({
|
||||||
url: '/calendar/api/v1/event',
|
url: '/calendar/api/v1/events',
|
||||||
method: 'GET',
|
method: 'GET'
|
||||||
headers: headers
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const put_event = (id: number, data: {
|
||||||
|
eventDate: string
|
||||||
|
title: string
|
||||||
|
eventInfo?: string
|
||||||
|
}) => {
|
||||||
|
return service({
|
||||||
|
url: `/calendar/api/v1/events/${id}`,
|
||||||
|
method: 'PUT',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const delete_event = (id: number) => {
|
||||||
|
return service({
|
||||||
|
url: `/calendar/api/v1/events/${id}`,
|
||||||
|
method: 'DELETE'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
get_event,
|
get_event,
|
||||||
|
post_event,
|
||||||
put_event,
|
put_event,
|
||||||
}
|
delete_event,
|
||||||
|
}
|
||||||
|
|||||||
+9
-1
@@ -20,6 +20,13 @@ const update_profile = (data: Object) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const publish_profile = () => {
|
||||||
|
return service({
|
||||||
|
url: '/wiki/api/v1/author/profile/publish',
|
||||||
|
method: 'PUT'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const get_profile = () => {
|
const get_profile = () => {
|
||||||
return service({
|
return service({
|
||||||
url: '/wiki/api/v1/author/profile',
|
url: '/wiki/api/v1/author/profile',
|
||||||
@@ -51,5 +58,6 @@ export {
|
|||||||
get_profile,
|
get_profile,
|
||||||
update_profile,
|
update_profile,
|
||||||
get_profileName,
|
get_profileName,
|
||||||
judge_profile
|
judge_profile,
|
||||||
|
publish_profile
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { service } from '../utils/request'
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json;charsetset=UTF-8'
|
||||||
|
}
|
||||||
|
|
||||||
|
// To obtain the monthly data by year
|
||||||
|
const get_monthly_data = (year: string) => {
|
||||||
|
return service({
|
||||||
|
url: '/traderCalender/api/v1/trader/calender/year/' + year,
|
||||||
|
method: 'GET',
|
||||||
|
headers: headers,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// To update the monthly data by year
|
||||||
|
// const update_monthly_data = (data: object) => {
|
||||||
|
// return service({
|
||||||
|
// url: '/traderCalender/api/v1/trader/calender/year/' + year,
|
||||||
|
// method: 'POST',
|
||||||
|
// data: data
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
export { get_monthly_data }
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="headerAvatar">
|
<span class="headerAvatar">
|
||||||
<template v-if="picType === 'avatar'">
|
<template v-if="picType === 'avatar'">
|
||||||
<el-avatar v-if="useTenantStore.tenant.headerImg" :size="30" :src="avatar" />
|
<el-avatar v-if="useCustomerStore.customer.headerImg" :size="30" :src="avatar" />
|
||||||
<el-avatar v-else :size="30" :src="noAvatar" />
|
<el-avatar v-else :size="30" :src="noAvatar" />
|
||||||
</template>
|
</template>
|
||||||
<template v-if="picType === 'img'">
|
<template v-if="picType === 'img'">
|
||||||
<img v-if="useTenantStore.tenant.headerImg" :src="avatar" class="avatar">
|
<img v-if="useCustomerStore.customer.headerImg" :src="avatar" class="avatar">
|
||||||
<img v-else :src="noAvatar" class="avatar">
|
<img v-else :src="noAvatar" class="avatar">
|
||||||
</template>
|
</template>
|
||||||
<template v-if="picType === 'file'">
|
<template v-if="picType === 'file'">
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { tenantStore } from '@/store/modules/tenant'
|
import { customerStore } from '@/store/modules/customer'
|
||||||
import noAvatarPng from '@/assets/nobody.jpg'
|
import noAvatarPng from '@/assets/nobody.jpg'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -33,13 +33,13 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
const path = ref(import.meta.env.VITE_BASE_API + '/')
|
const path = ref(import.meta.env.VITE_BASE_API + '/')
|
||||||
const noAvatar = ref(noAvatarPng)
|
const noAvatar = ref(noAvatarPng)
|
||||||
const useTenantStore = tenantStore()
|
const useCustomerStore = customerStore()
|
||||||
const avatar = computed(() => {
|
const avatar = computed(() => {
|
||||||
if (props.picSrc === '') {
|
if (props.picSrc === '') {
|
||||||
if (useTenantStore.tenant.headerImg !== '' && useTenantStore.tenant.headerImg.slice(0, 4) === 'http') {
|
if (useCustomerStore.customer.headerImg !== '' && useCustomerStore.customer.headerImg.slice(0, 4) === 'http') {
|
||||||
return useTenantStore.tenant.headerImg
|
return useCustomerStore.customer.headerImg
|
||||||
}
|
}
|
||||||
return path.value + useTenantStore.tenant.headerImg
|
return path.value + useCustomerStore.customer.headerImg
|
||||||
} else {
|
} else {
|
||||||
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
|
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
|
||||||
return props.picSrc
|
return props.picSrc
|
||||||
@@ -61,7 +61,6 @@ const file = computed(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file {
|
.file {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
|
|||||||
@@ -12,12 +12,14 @@
|
|||||||
<MainApp></MainApp>
|
<MainApp></MainApp>
|
||||||
</el-main>
|
</el-main>
|
||||||
<el-footer>
|
<el-footer>
|
||||||
<span>
|
<div class="footer-left">
|
||||||
管祥玮的个人网站 ©Copyright 2022-2022
|
<span>{{ SITE_NAME }} {{ COPYRIGHT_TEXT }}</span>
|
||||||
</span>
|
<span class="separator">|</span>
|
||||||
<span @click="openSiteQuery">辽ICP备2022003637号-2</span>
|
<span class="icp-link" @click="openSiteQuery">{{ ICP_NUMBER }}</span>
|
||||||
<div>
|
</div>
|
||||||
<el-avatar @click="openGithub" src="https://github.githubassets.com/favicons/favicon.svg" />
|
<div class="footer-right">
|
||||||
|
<el-avatar :size="24" class="github-icon" @click="openGithub"
|
||||||
|
src="https://github.githubassets.com/favicons/favicon.svg" />
|
||||||
</div>
|
</div>
|
||||||
</el-footer>
|
</el-footer>
|
||||||
</el-container>
|
</el-container>
|
||||||
@@ -30,6 +32,7 @@ import MainApp from '../layout/MainApp.vue'
|
|||||||
import NavBar from "../layout/NavBar.vue"
|
import NavBar from "../layout/NavBar.vue"
|
||||||
import SideBar from "../layout/SideBar.vue"
|
import SideBar from "../layout/SideBar.vue"
|
||||||
import { settingsStore } from "@/store/modules/settings"
|
import { settingsStore } from "@/store/modules/settings"
|
||||||
|
import { SITE_NAME, COPYRIGHT_TEXT, ICP_NUMBER, ICP_QUERY_URL } from "@/const/site"
|
||||||
|
|
||||||
// -- IMPORT --
|
// -- IMPORT --
|
||||||
const useSettingsStore = settingsStore()
|
const useSettingsStore = settingsStore()
|
||||||
@@ -62,8 +65,7 @@ const openGithub = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const openSiteQuery = () => {
|
const openSiteQuery = () => {
|
||||||
let href = 'https://beian.miit.gov.cn/#/Integrated/index'
|
window.open(ICP_QUERY_URL, '_blank')
|
||||||
window.open(href, '_blank')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,9 +83,12 @@ iniPage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
.el-main {
|
.el-main {
|
||||||
|
/* 让 main 区占满 header 与 footer 之间的剩余空间,
|
||||||
|
内容多了 main 内部滚动,footer 永远钉在 layout 底部 */
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
overflow: hidden;
|
flex: 1;
|
||||||
height: 100%;
|
min-height: 0; /* flex item 默认 min-height: auto 会阻止收缩 */
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-aside {
|
.el-aside {
|
||||||
@@ -93,13 +98,50 @@ iniPage()
|
|||||||
}
|
}
|
||||||
|
|
||||||
.el-footer {
|
.el-footer {
|
||||||
|
/* flex: 0 0 auto 让 footer 保持自身高度(不撑开、不收缩) */
|
||||||
|
flex: 0 0 auto;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-top: 1px solid rgba(151, 151, 151, 0.2);
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icp-link {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icp-link:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-icon {
|
||||||
|
/* 跟 footer 文字 baseline 对齐 */
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main_container {
|
.main_container {
|
||||||
/* height: 100%; */
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.homeWrap {
|
.homeWrap {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
<span class="header-avatar" style="cursor: pointer">
|
<span class="header-avatar" style="cursor: pointer">
|
||||||
<CustomPic />
|
<CustomPic />
|
||||||
<span v-show="!useSettingsStore.isMobile" style="margin-left: 5px">{{
|
<span v-show="!useSettingsStore.isMobile" style="margin-left: 5px">{{
|
||||||
useTenantStore.tenant.account
|
useCustomerStore.customer.account
|
||||||
}}</span>
|
}}</span>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<arrow-down />
|
<arrow-down />
|
||||||
@@ -67,10 +67,10 @@
|
|||||||
<el-dropdown-menu class="dropdown-group">
|
<el-dropdown-menu class="dropdown-group">
|
||||||
<el-dropdown-item>
|
<el-dropdown-item>
|
||||||
<span style="font-weight: 600;">
|
<span style="font-weight: 600;">
|
||||||
当前角色:{{ useTenantStore.tenant.account }}
|
当前角色:{{ useCustomerStore.customer.account }}
|
||||||
</span>
|
</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<template v-if="useTenantStore.tenant.account">
|
<template v-if="useCustomerStore.customer.account">
|
||||||
<!-- <el-dropdown-item v-for="item in userStore.userInfo.authorities.filter(i=>i.authorityId!==userStore.userInfo.authorityId)" :key="item.authorityId" @click="changeUserAuth(item.authorityId)">
|
<!-- <el-dropdown-item v-for="item in userStore.userInfo.authorities.filter(i=>i.authorityId!==userStore.userInfo.authorityId)" :key="item.authorityId" @click="changeUserAuth(item.authorityId)">
|
||||||
<span>
|
<span>
|
||||||
切换为:{{ item.authorityName }}
|
切换为:{{ item.authorityName }}
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
</el-dropdown-item> -->
|
</el-dropdown-item> -->
|
||||||
</template>
|
</template>
|
||||||
<el-dropdown-item icon="avatar" @click="toPerson">个人信息</el-dropdown-item>
|
<el-dropdown-item icon="avatar" @click="toPerson">个人信息</el-dropdown-item>
|
||||||
<el-dropdown-item icon="reading-lamp" @click="useTenantStore.logout">登 出</el-dropdown-item>
|
<el-dropdown-item icon="reading-lamp" @click="useCustomerStore.logout">登 出</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
@@ -89,13 +89,13 @@
|
|||||||
|
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import CustomPic from "@/components/customPic/index.vue";
|
import CustomPic from "@/components/customPic/index.vue";
|
||||||
import { tenantStore } from '@/store/modules/tenant'
|
import { customerStore } from '@/store/modules/customer'
|
||||||
import { settingsStore } from '@/store/modules/settings'
|
import { settingsStore } from '@/store/modules/settings'
|
||||||
import { Message } from "@element-plus/icons-vue"
|
import { Message } from "@element-plus/icons-vue"
|
||||||
import { reactive, ref } from "vue";
|
import { reactive, ref } from "vue";
|
||||||
|
|
||||||
// -- IMPORT --
|
// -- IMPORT --
|
||||||
const useTenantStore = tenantStore()
|
const useCustomerStore = customerStore()
|
||||||
const useSettingsStore = settingsStore()
|
const useSettingsStore = settingsStore()
|
||||||
|
|
||||||
// -- REACTIVE OBJECT --
|
// -- REACTIVE OBJECT --
|
||||||
@@ -131,7 +131,7 @@ const toPerson = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
useTenantStore.reflush()
|
useCustomerStore.reflush()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
+106
-72
@@ -1,84 +1,65 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="yuliu" :style="style">
|
<div class="ttt">
|
||||||
</div>
|
<div class="yuliu" :style="style">
|
||||||
<el-card class="box-card">
|
|
||||||
|
|
||||||
<el-form ref="ruleFormRef" :model="loginForm" :rules="loginRules" status-icon label-width="120px"
|
|
||||||
class="demo-ruleForm">
|
|
||||||
<div class="title-container">
|
|
||||||
<h3>秘密基地</h3>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<el-avatar :size="28" :src="baiduCloudImage" @click="scan(qrcode)" />
|
|
||||||
</div>
|
|
||||||
<el-form-item>
|
|
||||||
其他登录方式暂时还没有哦
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
------------------------------------------------------------
|
|
||||||
<div>
|
|
||||||
微信/支付宝
|
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
<el-card class="box-card">
|
||||||
|
|
||||||
|
<el-form>
|
||||||
|
<div class="title-container">
|
||||||
|
<h3>秘密基地</h3>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" size="large" @click="handleOidcLogin">统一登录</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
------------------------------------------------------------
|
||||||
|
<div>
|
||||||
|
微信/支付宝
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="footer-left">
|
||||||
|
<span>{{ SITE_NAME }} {{ COPYRIGHT_TEXT }}</span>
|
||||||
|
<span class="separator">|</span>
|
||||||
|
<span class="icp-link" @click="openSiteQuery">{{ ICP_NUMBER }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="footer-right">
|
||||||
|
<el-avatar :size="24" class="github-icon" @click="openGithub"
|
||||||
|
src="https://github.githubassets.com/favicons/favicon.svg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import type { FormInstance } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { tenantStore } from '../../store/modules/tenant'
|
import { SITE_NAME, COPYRIGHT_TEXT, ICP_NUMBER, ICP_QUERY_URL } from '@/const/site'
|
||||||
import router from '../../router'
|
|
||||||
import baiduCloudImage from "../../assets/baiducloud.png"
|
|
||||||
import { config, scan } from '../../const/config'
|
|
||||||
|
|
||||||
|
const handleOidcLogin = () => {
|
||||||
|
const issuer = import.meta.env.VITE_OIDC_ISSUER
|
||||||
|
const clientId = import.meta.env.VITE_OIDC_CLIENT_ID
|
||||||
|
const redirectUri = encodeURIComponent(import.meta.env.VITE_OIDC_REDIRECT_URI)
|
||||||
|
const scope = encodeURIComponent('openid profile email')
|
||||||
|
const state = Math.random().toString(36).substring(2)
|
||||||
|
|
||||||
let qrcode = config.BAIDU_CLOUD_URL + config.RESPONSE_TYPE + config.CLIENT_ID + config.REDIRECT_URI + config.SCOPE + config.DEVICE_ID + config.QR_CODE + config.DISPLAY
|
if (!issuer || !clientId) {
|
||||||
|
ElMessage.error('OIDC 未配置,请联系管理员')
|
||||||
const useTenantStore = tenantStore()
|
|
||||||
|
|
||||||
const ruleFormRef = ref<FormInstance>()
|
|
||||||
const loginForm = reactive({
|
|
||||||
user_id: '',
|
|
||||||
password: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const validateUserName = (rule: any, value: string, callback: Function) => {
|
|
||||||
if (!value) {
|
|
||||||
callback(new Error("请输入的用户名"))
|
|
||||||
} else {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const validatePassword = (rule: any, value: string, callback: Function) => {
|
|
||||||
if (!value) {
|
|
||||||
callback(new Error("请输入密码"))
|
|
||||||
} else {
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const loginRules = reactive({
|
|
||||||
user_id: [{ validator: validateUserName, trigger: 'blur' }],
|
|
||||||
password: [{ validator: validatePassword, trigger: 'blur' }]
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const dologin = (form: any) => {
|
|
||||||
|
|
||||||
if (!form)
|
|
||||||
return
|
return
|
||||||
// form.validate((valid: any) => {
|
}
|
||||||
// if (valid) {
|
|
||||||
// useTenantStore.login(loginForm.user_id, loginForm.password).then(res => {
|
|
||||||
// console.log(1)
|
|
||||||
// router.push({
|
|
||||||
// path: '/home'
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// } else {
|
sessionStorage.setItem('oidc_state', state)
|
||||||
// return false
|
window.location.href =
|
||||||
// }
|
`${issuer}/application/o/authorize/?` +
|
||||||
// })
|
`client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const openSiteQuery = () => {
|
||||||
|
window.open(ICP_QUERY_URL, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
const openGithub = () => {
|
||||||
|
window.open('https://github.com/simple321vip', '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
const style = reactive({} as any)
|
const style = reactive({} as any)
|
||||||
@@ -94,12 +75,65 @@ style.width = window.innerWidth * 0.7 + 'px'
|
|||||||
padding: 18px 0;
|
padding: 18px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ttt {
|
||||||
|
/* flex column + min-height 100vh:footer 永远在视口底部,
|
||||||
|
内容少时 footer 贴底,内容多时 footer 在内容之后但不漂 */
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.yuliu {
|
.yuliu {
|
||||||
/* width: 600px; */
|
/* width: 600px; */
|
||||||
height: 600px;
|
height: 300px;
|
||||||
float: left;
|
float: left;
|
||||||
/* background-color: antiquewhite; */
|
/* background-color: antiquewhite; */
|
||||||
background: url('../../assets/have_a_nice_day.jpeg') center top no-repeat;
|
background: url('../../assets/have_a_nice_day.jpeg') center top no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box-card {
|
||||||
|
/* 中间内容区撑开剩余空间 */
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-top: 1px solid rgba(151, 151, 151, 0.2);
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icp-link {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icp-link:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
<el-input v-model="register_form.code" />
|
<el-input v-model="register_form.code" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="tenantId">
|
<el-form-item label="customerId">
|
||||||
<el-input v-model="register_form.tenant_id" :disabled="true" />
|
<el-input v-model="register_form.customerId" :disabled="true" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="account">
|
<el-form-item label="account">
|
||||||
@@ -35,17 +35,17 @@ import { reactive } from 'vue'
|
|||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { register_user } from "./../../api/user";
|
import { register_user } from "./../../api/user";
|
||||||
import router from '../../router/index'
|
import router from '../../router/index'
|
||||||
import { setTenant, setToken } from '../../utils/auth';
|
import { setCustomer, setToken } from '../../utils/auth';
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const params = route.query
|
const params = route.query
|
||||||
|
|
||||||
|
|
||||||
// use phone number to register user(tenant)
|
// use phone number to register user(customer)
|
||||||
const register_form = reactive({
|
const register_form = reactive({
|
||||||
phone_number: '',
|
phone_number: '',
|
||||||
code: '',
|
code: '',
|
||||||
tenant_id: params.tenantId as string,
|
customerId: params.customerId as string,
|
||||||
account: params.account as string,
|
account: params.account as string,
|
||||||
token: params.token as string
|
token: params.token as string
|
||||||
})
|
})
|
||||||
@@ -54,13 +54,13 @@ const onSubmit = () => {
|
|||||||
register_user(register_form).then((response) => {
|
register_user(register_form).then((response) => {
|
||||||
|
|
||||||
if (response.status == 200) {
|
if (response.status == 200) {
|
||||||
const tenant = {
|
const customer = {
|
||||||
id: params.tenantId,
|
id: params.customerId,
|
||||||
account: params.account
|
account: params.account
|
||||||
}
|
}
|
||||||
|
|
||||||
setToken(params.token as string)
|
setToken(params.token as string)
|
||||||
setTenant(tenant)
|
setCustomer(customer)
|
||||||
|
|
||||||
const { href } = router.resolve({
|
const { href } = router.resolve({
|
||||||
path: '/'
|
path: '/'
|
||||||
@@ -74,4 +74,4 @@ const onSubmit = () => {
|
|||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
+10
-10
@@ -1,7 +1,7 @@
|
|||||||
import { Tenant } from '@/entity';
|
import { Customer } from '@/entity';
|
||||||
import { tenantStore } from '@/store/modules/tenant';
|
import { customerStore } from '@/store/modules/customer';
|
||||||
import router from '../router'
|
import router from '../router'
|
||||||
import { setToken, setTenant } from '../utils/auth'
|
import { setToken, setCustomer } from '../utils/auth'
|
||||||
|
|
||||||
// config/index.js
|
// config/index.js
|
||||||
const env = process.env.NODE_ENV!;
|
const env = process.env.NODE_ENV!;
|
||||||
@@ -45,14 +45,14 @@ const scan_method: any = {
|
|||||||
},
|
},
|
||||||
development: async () => {
|
development: async () => {
|
||||||
|
|
||||||
const useTenantStore = tenantStore()
|
const useCustomerStore = customerStore()
|
||||||
const tenant: Tenant = {
|
const customer: Customer = {
|
||||||
tenant_id: '7788',
|
customerId: '7788',
|
||||||
account: '小小的测试账户'
|
account: '小小的测试账户'
|
||||||
}
|
}
|
||||||
let token = 'ABCDEFG'
|
let token = 'ABCDEFG'
|
||||||
|
|
||||||
await useTenantStore.login(tenant, token).then(() => {
|
await useCustomerStore.login(customer, token).then(() => {
|
||||||
const { href } = router.resolve({
|
const { href } = router.resolve({
|
||||||
path: '/'
|
path: '/'
|
||||||
})
|
})
|
||||||
@@ -65,9 +65,9 @@ const scan_method: any = {
|
|||||||
})
|
})
|
||||||
|
|
||||||
setToken("token")
|
setToken("token")
|
||||||
setTenant(
|
setCustomer(
|
||||||
{
|
{
|
||||||
tenantId: "111"
|
customerId: "111"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
router.push({
|
router.push({
|
||||||
@@ -82,4 +82,4 @@ const scan_method: any = {
|
|||||||
const scan = scan_method[env]
|
const scan = scan_method[env]
|
||||||
const config = configObj[env]
|
const config = configObj[env]
|
||||||
|
|
||||||
export { scan, config }
|
export { scan, config }
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* 站点元信息常量。
|
||||||
|
*
|
||||||
|
* <p>⚠️ ICP 备案号是公网安部要求强制展示的,<b>不能修改</b>。文案变更需重新备案。</p>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 产品名(footer / 浏览器 title / 侧边栏使用) */
|
||||||
|
export const SITE_NAME = 'Violin Home'
|
||||||
|
|
||||||
|
/** 版权年份区间(自动取当前年) */
|
||||||
|
export const COPYRIGHT_YEARS = `2022-${new Date().getFullYear()}`
|
||||||
|
|
||||||
|
/** 完整版权字符串(footer 用) */
|
||||||
|
export const COPYRIGHT_TEXT = `©Copyright ${COPYRIGHT_YEARS}`
|
||||||
|
|
||||||
|
/** ICP 备案号(⚠️ 公网安部要求原样显示,不可修改) */
|
||||||
|
export const ICP_NUMBER = '辽ICP备2022003637号-2'
|
||||||
|
|
||||||
|
/** ICP 备案查询 URL(公网安部要求链接到工信部查询页) */
|
||||||
|
export const ICP_QUERY_URL = 'https://beian.miit.gov.cn/#/Integrated/index'
|
||||||
+12
-7
@@ -1,5 +1,5 @@
|
|||||||
type Tenant = {
|
type Customer = {
|
||||||
tenant_id: string,
|
customerId: string,
|
||||||
account: string
|
account: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,11 +19,15 @@ type DataTimeline = {
|
|||||||
message: string,
|
message: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 与后端 CalendarEventResponse 对齐(camelCase)
|
||||||
type Event = {
|
type Event = {
|
||||||
reminder_date: string,
|
id?: number
|
||||||
title: string,
|
customerId?: string
|
||||||
info: string,
|
eventDate: string
|
||||||
type: string[],
|
title: string
|
||||||
|
eventInfo?: string
|
||||||
|
createdAt?: string
|
||||||
|
updatedAt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Wiki {
|
interface Wiki {
|
||||||
@@ -64,4 +68,5 @@ const wikiType = (data: any) => {
|
|||||||
} as WikiType
|
} as WikiType
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Tenant, Theme, DataTimeline, Event, Wiki, wiki, WikiType, wikiType }
|
export type { Customer, Theme, DataTimeline, Event, Wiki, WikiType }
|
||||||
|
export { wiki, wikiType }
|
||||||
|
|||||||
Vendored
+11
@@ -6,3 +6,14 @@ declare module '*.vue' {
|
|||||||
const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>
|
||||||
export default component
|
export default component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 兼容 element-plus 2.8.x 与 vue-tsc 2.x 的 GlobalComponents 索引类型
|
||||||
|
// (element-plus 在 .d.ts 里把 GlobalComponents 用作 Record<string, Component<...>>,
|
||||||
|
// 但 vue 默认声明没提供 index signature,触发 TS2344)
|
||||||
|
declare module 'vue' {
|
||||||
|
interface GlobalComponents {
|
||||||
|
[elemName: string]: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user