引入tailwindCss
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||||
"@ant-design/colors": "^6.0.0",
|
"@ant-design/colors": "^6.0.0",
|
||||||
"@ant-design/icons-vue": "^6.1.0",
|
"@ant-design/icons-vue": "^6.1.0",
|
||||||
|
"@antv/g2": "^5.1.22",
|
||||||
"@bytemd/plugin-gfm": "^1.17.2",
|
"@bytemd/plugin-gfm": "^1.17.2",
|
||||||
"@bytemd/plugin-highlight": "^1.17.4",
|
"@bytemd/plugin-highlight": "^1.17.4",
|
||||||
"@bytemd/plugin-highlight-ssr": "^1.20.2",
|
"@bytemd/plugin-highlight-ssr": "^1.20.2",
|
||||||
|
|||||||
106
src/api/booking/cooperate/index.ts
Normal file
106
src/api/booking/cooperate/index.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api';
|
||||||
|
import type { Cooperate, CooperateParam } from './model';
|
||||||
|
import { MODULES_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询商务合作
|
||||||
|
*/
|
||||||
|
export async function pageCooperate(params: CooperateParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<Cooperate>>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate/page',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询商务合作列表
|
||||||
|
*/
|
||||||
|
export async function listCooperate(params?: CooperateParam) {
|
||||||
|
const res = await request.get<ApiResult<Cooperate[]>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加商务合作
|
||||||
|
*/
|
||||||
|
export async function addCooperate(data: Cooperate) {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改商务合作
|
||||||
|
*/
|
||||||
|
export async function updateCooperate(data: Cooperate) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除商务合作
|
||||||
|
*/
|
||||||
|
export async function removeCooperate(id?: number) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除商务合作
|
||||||
|
*/
|
||||||
|
export async function removeBatchCooperate(data: (number | undefined)[]) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate/batch',
|
||||||
|
{
|
||||||
|
data
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询商务合作
|
||||||
|
*/
|
||||||
|
export async function getCooperate(id: number) {
|
||||||
|
const res = await request.get<ApiResult<Cooperate>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
33
src/api/booking/cooperate/model/index.ts
Normal file
33
src/api/booking/cooperate/model/index.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import type { PageParam } from '@/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商务合作
|
||||||
|
*/
|
||||||
|
export interface Cooperate {
|
||||||
|
// ID
|
||||||
|
cooperateId?: number;
|
||||||
|
// 部门名称
|
||||||
|
name?: string;
|
||||||
|
// 咨询电话
|
||||||
|
phone?: string;
|
||||||
|
// 图片
|
||||||
|
image?: string;
|
||||||
|
// 备注
|
||||||
|
comments?: string;
|
||||||
|
// 状态
|
||||||
|
status?: number;
|
||||||
|
// 排序号
|
||||||
|
sortNumber?: number;
|
||||||
|
// 租户id
|
||||||
|
tenantId?: number;
|
||||||
|
// 创建时间
|
||||||
|
createTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商务合作搜索条件
|
||||||
|
*/
|
||||||
|
export interface CooperateParam extends PageParam {
|
||||||
|
cooperateId?: number;
|
||||||
|
keywords?: string;
|
||||||
|
}
|
||||||
106
src/api/booking/cooperateLog/index.ts
Normal file
106
src/api/booking/cooperateLog/index.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api';
|
||||||
|
import type { CooperateLog, CooperateLogParam } from './model';
|
||||||
|
import { MODULES_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询商务合作留言记录
|
||||||
|
*/
|
||||||
|
export async function pageCooperateLog(params: CooperateLogParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<CooperateLog>>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate-log/page',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询商务合作留言记录列表
|
||||||
|
*/
|
||||||
|
export async function listCooperateLog(params?: CooperateLogParam) {
|
||||||
|
const res = await request.get<ApiResult<CooperateLog[]>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate-log',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加商务合作留言记录
|
||||||
|
*/
|
||||||
|
export async function addCooperateLog(data: CooperateLog) {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate-log',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改商务合作留言记录
|
||||||
|
*/
|
||||||
|
export async function updateCooperateLog(data: CooperateLog) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate-log',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除商务合作留言记录
|
||||||
|
*/
|
||||||
|
export async function removeCooperateLog(id?: number) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate-log/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除商务合作留言记录
|
||||||
|
*/
|
||||||
|
export async function removeBatchCooperateLog(data: (number | undefined)[]) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate-log/batch',
|
||||||
|
{
|
||||||
|
data
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询商务合作留言记录
|
||||||
|
*/
|
||||||
|
export async function getCooperateLog(id: number) {
|
||||||
|
const res = await request.get<ApiResult<CooperateLog>>(
|
||||||
|
MODULES_API_URL + '/booking/cooperate-log/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
35
src/api/booking/cooperateLog/model/index.ts
Normal file
35
src/api/booking/cooperateLog/model/index.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import type { PageParam } from '@/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商务合作留言记录
|
||||||
|
*/
|
||||||
|
export interface CooperateLog {
|
||||||
|
// ID
|
||||||
|
logId?: number;
|
||||||
|
// 关联ID
|
||||||
|
cooperateId?: number;
|
||||||
|
// 部门名称
|
||||||
|
name?: string;
|
||||||
|
// 咨询电话
|
||||||
|
phone?: string;
|
||||||
|
// 图片
|
||||||
|
image?: string;
|
||||||
|
// 备注
|
||||||
|
comments?: string;
|
||||||
|
// 状态
|
||||||
|
status?: number;
|
||||||
|
// 排序号
|
||||||
|
sortNumber?: number;
|
||||||
|
// 租户id
|
||||||
|
tenantId?: number;
|
||||||
|
// 创建时间
|
||||||
|
createTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商务合作留言记录搜索条件
|
||||||
|
*/
|
||||||
|
export interface CooperateLogParam extends PageParam {
|
||||||
|
logId?: number;
|
||||||
|
keywords?: string;
|
||||||
|
}
|
||||||
106
src/api/booking/match/index.ts
Normal file
106
src/api/booking/match/index.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api';
|
||||||
|
import type { Match, MatchParam } from './model';
|
||||||
|
import { MODULES_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询比赛信息表
|
||||||
|
*/
|
||||||
|
export async function pageMatch(params: MatchParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<Match>>>(
|
||||||
|
MODULES_API_URL + '/booking/match/page',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询比赛信息表列表
|
||||||
|
*/
|
||||||
|
export async function listMatch(params?: MatchParam) {
|
||||||
|
const res = await request.get<ApiResult<Match[]>>(
|
||||||
|
MODULES_API_URL + '/booking/match',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加比赛信息表
|
||||||
|
*/
|
||||||
|
export async function addMatch(data: Match) {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改比赛信息表
|
||||||
|
*/
|
||||||
|
export async function updateMatch(data: Match) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除比赛信息表
|
||||||
|
*/
|
||||||
|
export async function removeMatch(id?: number) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除比赛信息表
|
||||||
|
*/
|
||||||
|
export async function removeBatchMatch(data: (number | undefined)[]) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match/batch',
|
||||||
|
{
|
||||||
|
data
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询比赛信息表
|
||||||
|
*/
|
||||||
|
export async function getMatch(id: number) {
|
||||||
|
const res = await request.get<ApiResult<Match>>(
|
||||||
|
MODULES_API_URL + '/booking/match/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
73
src/api/booking/match/model/index.ts
Normal file
73
src/api/booking/match/model/index.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import type { PageParam } from '@/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比赛信息表
|
||||||
|
*/
|
||||||
|
export interface Match {
|
||||||
|
// 赛事ID
|
||||||
|
matchId?: number;
|
||||||
|
// 标题
|
||||||
|
title?: string;
|
||||||
|
// 比赛类型 0常规比赛
|
||||||
|
type?: number;
|
||||||
|
// 活动开始时间
|
||||||
|
matchStartTime?: number;
|
||||||
|
// 活动结束时间
|
||||||
|
matchEndTime?: number;
|
||||||
|
// 报名时间
|
||||||
|
bmStartTime?: number;
|
||||||
|
// 报名时间
|
||||||
|
bmEndTime?: number;
|
||||||
|
// 文章分类ID
|
||||||
|
categoryId?: number;
|
||||||
|
// 封面图
|
||||||
|
image?: string;
|
||||||
|
// 虚拟阅读量(仅用作展示)
|
||||||
|
virtualViews?: number;
|
||||||
|
// 实际阅读量
|
||||||
|
actualViews?: number;
|
||||||
|
// 文章附件
|
||||||
|
files?: string;
|
||||||
|
// 视频地址
|
||||||
|
video?: string;
|
||||||
|
// 退费规则
|
||||||
|
refundRule?: string;
|
||||||
|
// 活动介绍
|
||||||
|
content?: string;
|
||||||
|
// 经度
|
||||||
|
longitude?: string;
|
||||||
|
// 纬度
|
||||||
|
latitude?: string;
|
||||||
|
// 比赛活动地点
|
||||||
|
address?: string;
|
||||||
|
// 报名费用
|
||||||
|
price?: string;
|
||||||
|
// 已报名人数
|
||||||
|
users?: number;
|
||||||
|
// 报名人数限制
|
||||||
|
maxUsers?: number;
|
||||||
|
// 用户ID
|
||||||
|
userId?: number;
|
||||||
|
// 排序(数字越小越靠前)
|
||||||
|
sortNumber?: number;
|
||||||
|
// 备注
|
||||||
|
comments?: string;
|
||||||
|
// 状态, 0未开始, 1进行中,2已结束
|
||||||
|
status?: number;
|
||||||
|
// 是否删除, 0否, 1是
|
||||||
|
deleted?: number;
|
||||||
|
// 租户id
|
||||||
|
tenantId?: number;
|
||||||
|
// 注册时间
|
||||||
|
createTime?: string;
|
||||||
|
// 修改时间
|
||||||
|
updateTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比赛信息表搜索条件
|
||||||
|
*/
|
||||||
|
export interface MatchParam extends PageParam {
|
||||||
|
matchId?: number;
|
||||||
|
keywords?: string;
|
||||||
|
}
|
||||||
106
src/api/booking/matchOrder/index.ts
Normal file
106
src/api/booking/matchOrder/index.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import type { ApiResult, PageResult } from '@/api';
|
||||||
|
import type { MatchOrder, MatchOrderParam } from './model';
|
||||||
|
import { MODULES_API_URL } from '@/config/setting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询比赛报名记录表
|
||||||
|
*/
|
||||||
|
export async function pageMatchOrder(params: MatchOrderParam) {
|
||||||
|
const res = await request.get<ApiResult<PageResult<MatchOrder>>>(
|
||||||
|
MODULES_API_URL + '/booking/match-order/page',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询比赛报名记录表列表
|
||||||
|
*/
|
||||||
|
export async function listMatchOrder(params?: MatchOrderParam) {
|
||||||
|
const res = await request.get<ApiResult<MatchOrder[]>>(
|
||||||
|
MODULES_API_URL + '/booking/match-order',
|
||||||
|
{
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加比赛报名记录表
|
||||||
|
*/
|
||||||
|
export async function addMatchOrder(data: MatchOrder) {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match-order',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改比赛报名记录表
|
||||||
|
*/
|
||||||
|
export async function updateMatchOrder(data: MatchOrder) {
|
||||||
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match-order',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除比赛报名记录表
|
||||||
|
*/
|
||||||
|
export async function removeMatchOrder(id?: number) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match-order/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除比赛报名记录表
|
||||||
|
*/
|
||||||
|
export async function removeBatchMatchOrder(data: (number | undefined)[]) {
|
||||||
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
|
MODULES_API_URL + '/booking/match-order/batch',
|
||||||
|
{
|
||||||
|
data
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return res.data.message;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询比赛报名记录表
|
||||||
|
*/
|
||||||
|
export async function getMatchOrder(id: number) {
|
||||||
|
const res = await request.get<ApiResult<MatchOrder>>(
|
||||||
|
MODULES_API_URL + '/booking/match-order/' + id
|
||||||
|
);
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
return res.data.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.data.message));
|
||||||
|
}
|
||||||
47
src/api/booking/matchOrder/model/index.ts
Normal file
47
src/api/booking/matchOrder/model/index.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import type { PageParam } from '@/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比赛报名记录表
|
||||||
|
*/
|
||||||
|
export interface MatchOrder {
|
||||||
|
// 赛事ID
|
||||||
|
matchOrderId?: number;
|
||||||
|
// 赛事ID
|
||||||
|
matchId?: number;
|
||||||
|
// 场次
|
||||||
|
session?: number;
|
||||||
|
// 比赛活动地点
|
||||||
|
address?: string;
|
||||||
|
// 姓名
|
||||||
|
name?: number;
|
||||||
|
// 性别
|
||||||
|
sex?: number;
|
||||||
|
// 身份证号码
|
||||||
|
idCardNo?: string;
|
||||||
|
// 手机号码
|
||||||
|
phone?: string;
|
||||||
|
// 用户ID
|
||||||
|
userId?: number;
|
||||||
|
// 排序(数字越小越靠前)
|
||||||
|
sortNumber?: number;
|
||||||
|
// 备注
|
||||||
|
comments?: string;
|
||||||
|
// 状态, 0未开始, 1进行中,2已结束
|
||||||
|
status?: number;
|
||||||
|
// 是否删除, 0否, 1是
|
||||||
|
deleted?: number;
|
||||||
|
// 租户id
|
||||||
|
tenantId?: number;
|
||||||
|
// 注册时间
|
||||||
|
createTime?: string;
|
||||||
|
// 修改时间
|
||||||
|
updateTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比赛报名记录表搜索条件
|
||||||
|
*/
|
||||||
|
export interface MatchOrderParam extends PageParam {
|
||||||
|
matchOrderId?: number;
|
||||||
|
keywords?: string;
|
||||||
|
}
|
||||||
185
src/api/dashboard/analysis/20200610/analysis-hot-search.json
Executable file
185
src/api/dashboard/analysis/20200610/analysis-hot-search.json
Executable file
@@ -0,0 +1,185 @@
|
|||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "软妹子",
|
||||||
|
"value": 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "汪星人",
|
||||||
|
"value": 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "长腿欧巴",
|
||||||
|
"value": 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "萝莉",
|
||||||
|
"value": 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "辣~",
|
||||||
|
"value": 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "K歌",
|
||||||
|
"value": 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "大长腿",
|
||||||
|
"value": 21
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "川妹子",
|
||||||
|
"value": 21
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "女神",
|
||||||
|
"value": 21
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "米粉",
|
||||||
|
"value": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "专注设计",
|
||||||
|
"value": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "逛街",
|
||||||
|
"value": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "黑长直",
|
||||||
|
"value": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "海纳百川",
|
||||||
|
"value": 19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "萌萌哒",
|
||||||
|
"value": 19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "坚持",
|
||||||
|
"value": 19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "话唠",
|
||||||
|
"value": 19
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "果粉",
|
||||||
|
"value": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "喵星人",
|
||||||
|
"value": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "花粉",
|
||||||
|
"value": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "衬衫控",
|
||||||
|
"value": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "宅男",
|
||||||
|
"value": 17
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "小清新",
|
||||||
|
"value": 17
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "眼镜男",
|
||||||
|
"value": 17
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "琼瑶",
|
||||||
|
"value": 17
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "穷游党",
|
||||||
|
"value": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "铲屎官",
|
||||||
|
"value": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "正太",
|
||||||
|
"value": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中二病",
|
||||||
|
"value": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "夜猫子",
|
||||||
|
"value": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "逗比",
|
||||||
|
"value": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "腹黑",
|
||||||
|
"value": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "吃鸡",
|
||||||
|
"value": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "为了联盟",
|
||||||
|
"value": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "背包客",
|
||||||
|
"value": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "民谣",
|
||||||
|
"value": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "为了部落",
|
||||||
|
"value": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "懒癌患者",
|
||||||
|
"value": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "追剧",
|
||||||
|
"value": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IT民工",
|
||||||
|
"value": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CNB成员",
|
||||||
|
"value": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "选择困难",
|
||||||
|
"value": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "锤粉",
|
||||||
|
"value": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "欧皇",
|
||||||
|
"value": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "仙气十足",
|
||||||
|
"value": 12
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
73
src/api/dashboard/analysis/20200610/analysis-pay-num.json
Executable file
73
src/api/dashboard/analysis/20200610/analysis-pay-num.json
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"date": "2020-06-12",
|
||||||
|
"value": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-13",
|
||||||
|
"value": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-14",
|
||||||
|
"value": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-15",
|
||||||
|
"value": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-16",
|
||||||
|
"value": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-17",
|
||||||
|
"value": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-18",
|
||||||
|
"value": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-19",
|
||||||
|
"value": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-20",
|
||||||
|
"value": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-21",
|
||||||
|
"value": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-22",
|
||||||
|
"value": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-23",
|
||||||
|
"value": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-24",
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-25",
|
||||||
|
"value": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-26",
|
||||||
|
"value": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-27",
|
||||||
|
"value": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "2020-06-18",
|
||||||
|
"value": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
105
src/api/dashboard/analysis/20200610/analysis-saleroom.json
Executable file
105
src/api/dashboard/analysis/20200610/analysis-saleroom.json
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": {
|
||||||
|
"list1": [
|
||||||
|
{
|
||||||
|
"month": "1月",
|
||||||
|
"value": 816
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "2月",
|
||||||
|
"value": 542
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "3月",
|
||||||
|
"value": 914
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "4月",
|
||||||
|
"value": 781
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "5月",
|
||||||
|
"value": 355
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "6月",
|
||||||
|
"value": 796
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "7月",
|
||||||
|
"value": 714
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "8月",
|
||||||
|
"value": 1195
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "9月",
|
||||||
|
"value": 1055
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "10月",
|
||||||
|
"value": 271
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "11月",
|
||||||
|
"value": 384
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "12月",
|
||||||
|
"value": 1098
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"list2": [
|
||||||
|
{
|
||||||
|
"month": "1月",
|
||||||
|
"value": 1098
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "2月",
|
||||||
|
"value": 384
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "3月",
|
||||||
|
"value": 271
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "4月",
|
||||||
|
"value": 1055
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "5月",
|
||||||
|
"value": 1195
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "6月",
|
||||||
|
"value": 714
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "7月",
|
||||||
|
"value": 796
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "8月",
|
||||||
|
"value": 355
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "9月",
|
||||||
|
"value": 781
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "10月",
|
||||||
|
"value": 914
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "11月",
|
||||||
|
"value": 542
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"month": "12月",
|
||||||
|
"value": 816
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/api/dashboard/analysis/20200610/analysis-visits.json
Executable file
60
src/api/dashboard/analysis/20200610/analysis-visits.json
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"time": "16:00",
|
||||||
|
"visits": 15,
|
||||||
|
"views": 45
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:05",
|
||||||
|
"visits": 39,
|
||||||
|
"views": 169
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:10",
|
||||||
|
"visits": 152,
|
||||||
|
"views": 400
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:15",
|
||||||
|
"visits": 94,
|
||||||
|
"views": 285
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:20",
|
||||||
|
"visits": 102,
|
||||||
|
"views": 316
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:25",
|
||||||
|
"visits": 86,
|
||||||
|
"views": 148
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:30",
|
||||||
|
"visits": 39,
|
||||||
|
"views": 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:35",
|
||||||
|
"visits": 38,
|
||||||
|
"views": 234
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:40",
|
||||||
|
"visits": 95,
|
||||||
|
"views": 158
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:45",
|
||||||
|
"visits": 30,
|
||||||
|
"views": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": "16:50",
|
||||||
|
"visits": 86,
|
||||||
|
"views": 266
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { ApiResult } from '@/api';
|
import type { ApiResult } from '@/api';
|
||||||
import type { PayNumData, SaleroomResult, VisitData, CloudData } from './model';
|
import type { PayNumData, VisitData, CloudData } from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取支付笔数数据
|
* 获取支付笔数数据
|
||||||
*/
|
*/
|
||||||
export async function getPayNumList() {
|
export async function getPayNumList() {
|
||||||
const res = await request.get<ApiResult<PayNumData[]>>(
|
const res = await request.get<ApiResult<PayNumData[]>>(
|
||||||
'https://www.gxwebsoft.com/20200610/analysis-pay-num.json'
|
'./20200610/analysis-pay-num.json'
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
@@ -19,9 +19,10 @@ export async function getPayNumList() {
|
|||||||
* 获取销售量数据
|
* 获取销售量数据
|
||||||
*/
|
*/
|
||||||
export async function getSaleroomList() {
|
export async function getSaleroomList() {
|
||||||
const res = await request.get<ApiResult<SaleroomResult>>(
|
const fs = require('fs');
|
||||||
'https://www.gxwebsoft.com/20200610/analysis-saleroom.json'
|
const util = require('util');
|
||||||
);
|
const readFile = util.promisify(fs.readFile);
|
||||||
|
const res = await readFile('./20200610/analysis-saleroom.json');
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
}
|
}
|
||||||
@@ -34,7 +35,7 @@ export async function getSaleroomList() {
|
|||||||
*/
|
*/
|
||||||
export async function getVisitHourList() {
|
export async function getVisitHourList() {
|
||||||
const res = await request.get<ApiResult<VisitData[]>>(
|
const res = await request.get<ApiResult<VisitData[]>>(
|
||||||
'https://www.gxwebsoft.com/20200610/analysis-visits.json'
|
'./20200610/analysis-visits.json'
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
@@ -47,7 +48,7 @@ export async function getVisitHourList() {
|
|||||||
*/
|
*/
|
||||||
export async function getWordCloudList() {
|
export async function getWordCloudList() {
|
||||||
const res = await request.get<ApiResult<CloudData[]>>(
|
const res = await request.get<ApiResult<CloudData[]>>(
|
||||||
'https://www.gxwebsoft.com/20200610/analysis-hot-search.json'
|
'./20200610/analysis-hot-search.json'
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export async function getChinaMapData() {
|
|||||||
*/
|
*/
|
||||||
export async function getUserCountList() {
|
export async function getUserCountList() {
|
||||||
const res = await request.get<ApiResult<UserCount[]>>(
|
const res = await request.get<ApiResult<UserCount[]>>(
|
||||||
'https://www.gxwebsoft.com/20200610/monitor-user-count.json'
|
'https://cdn.eleadmin.com/20200610/monitor-user-count.json'
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
@@ -35,7 +35,7 @@ export async function getUserCountList() {
|
|||||||
*/
|
*/
|
||||||
export async function getBrowserCountList() {
|
export async function getBrowserCountList() {
|
||||||
const res = await request.get<ApiResult<BrowserCount[]>>(
|
const res = await request.get<ApiResult<BrowserCount[]>>(
|
||||||
'https://www.gxwebsoft.com/20200610/monitor-browser-count.json'
|
'https://cdn.eleadmin.com/20200610/monitor-browser-count.json'
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
<!-- 最新动态 -->
|
|
||||||
<template>
|
|
||||||
<a-card :title="title" :bordered="false" :body-style="{ padding: '6px 0' }">
|
|
||||||
<template #extra>
|
|
||||||
<more-icon @remove="onRemove" @edit="onEdit" />
|
|
||||||
</template>
|
|
||||||
<div
|
|
||||||
style="height: 346px; padding: 22px 20px 0 20px"
|
|
||||||
class="ele-scrollbar-hover"
|
|
||||||
>
|
|
||||||
<a-timeline>
|
|
||||||
<a-timeline-item
|
|
||||||
v-for="item in activities"
|
|
||||||
:key="item.id"
|
|
||||||
:color="item.color"
|
|
||||||
>
|
|
||||||
<em>{{ item.time }}</em>
|
|
||||||
<em>{{ item.title }}</em>
|
|
||||||
</a-timeline-item>
|
|
||||||
</a-timeline>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import MoreIcon from './more-icon.vue';
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
title?: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'remove'): void;
|
|
||||||
(e: 'edit'): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
interface Activitie {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
time: string;
|
|
||||||
color?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最新动态数据
|
|
||||||
const activities = ref<Activitie[]>([]);
|
|
||||||
|
|
||||||
/* 查询最新动态 */
|
|
||||||
const queryActivities = () => {
|
|
||||||
activities.value = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
title: 'SunSmile 解决了bug 登录提示操作失败',
|
|
||||||
time: '20:30',
|
|
||||||
color: 'gray'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: 'Jasmine 解决了bug 按钮颜色与设计不符',
|
|
||||||
time: '19:30',
|
|
||||||
color: 'gray'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
title: '项目经理 指派了任务 解决项目一的bug',
|
|
||||||
time: '18:30'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
title: '项目经理 指派了任务 解决项目二的bug',
|
|
||||||
time: '17:30'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
title: '项目经理 指派了任务 解决项目三的bug',
|
|
||||||
time: '16:30'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
title: '项目经理 指派了任务 解决项目四的bug',
|
|
||||||
time: '15:30',
|
|
||||||
color: 'gray'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
title: '项目经理 指派了任务 解决项目五的bug',
|
|
||||||
time: '14:30',
|
|
||||||
color: 'gray'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
title: '项目经理 指派了任务 解决项目六的bug',
|
|
||||||
time: '12:30',
|
|
||||||
color: 'gray'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
title: '项目经理 指派了任务 解决项目七的bug',
|
|
||||||
time: '11:30'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
title: '项目经理 指派了任务 解决项目八的bug',
|
|
||||||
time: '10:30',
|
|
||||||
color: 'gray'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
title: '项目经理 指派了任务 解决项目九的bug',
|
|
||||||
time: '09:30',
|
|
||||||
color: 'green'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
title: '项目经理 指派了任务 解决项目十的bug',
|
|
||||||
time: '08:30',
|
|
||||||
color: 'red'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const onRemove = () => {
|
|
||||||
emit('remove');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEdit = () => {
|
|
||||||
emit('edit');
|
|
||||||
};
|
|
||||||
|
|
||||||
queryActivities();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.ele-scrollbar-hover
|
|
||||||
:deep(.ant-timeline-item-last > .ant-timeline-item-content) {
|
|
||||||
min-height: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card :title="title" :bordered="false" :body-style="{ padding: '2px' }">
|
|
||||||
<template #extra
|
|
||||||
><a @click="openUrl('/oa/app/index')" class="ele-text-placeholder"
|
|
||||||
>更多<RightOutlined /></a
|
|
||||||
></template>
|
|
||||||
<a-list :size="`small`" :split="false" :data-source="list">
|
|
||||||
<template #renderItem="{ item }">
|
|
||||||
<a-list-item>
|
|
||||||
<div class="app-box">
|
|
||||||
<a-image
|
|
||||||
:height="45"
|
|
||||||
:width="45"
|
|
||||||
:preview="false"
|
|
||||||
:src="item.appIcon"
|
|
||||||
fallback="https://file.wsdns.cn/20230218/550e610d43334dd2a7f66d5b20bd58eb.svg"
|
|
||||||
/>
|
|
||||||
<div class="app-info">
|
|
||||||
<a
|
|
||||||
class="ele-text-heading"
|
|
||||||
@click="openNew('/oa/app/detail/' + item.appId)"
|
|
||||||
>
|
|
||||||
{{ item.appName }}
|
|
||||||
</a>
|
|
||||||
<span class="ele-text-placeholder">
|
|
||||||
{{ item.appCode }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-list-item>
|
|
||||||
</template>
|
|
||||||
</a-list>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { Article } from '@/api/cms/article/model';
|
|
||||||
import { openUrl } from '@/utils/common';
|
|
||||||
import { pageApp } from '@/api/oa/app';
|
|
||||||
import { RightOutlined } from '@ant-design/icons-vue';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
title: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const list = ref<Article[]>([]);
|
|
||||||
/**
|
|
||||||
* 加载数据
|
|
||||||
*/
|
|
||||||
const reload = () => {
|
|
||||||
const { title } = props;
|
|
||||||
// 加载文章列表
|
|
||||||
pageApp({
|
|
||||||
limit: 5,
|
|
||||||
status: 0,
|
|
||||||
appStatus: '开发中'
|
|
||||||
}).then((data) => {
|
|
||||||
if (data?.list) {
|
|
||||||
list.value = data.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
reload();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: 'DashboardArticleList'
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.app-box {
|
|
||||||
display: flex;
|
|
||||||
.app-info {
|
|
||||||
display: flex;
|
|
||||||
margin-left: 5px;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card :title="title" :bordered="false" :body-style="{ padding: '2px' }">
|
|
||||||
<template #extra
|
|
||||||
><a
|
|
||||||
@click="openNew('/cms/category/' + categoryId)"
|
|
||||||
class="ele-text-placeholder"
|
|
||||||
>更多<RightOutlined /></a
|
|
||||||
></template>
|
|
||||||
<a-list :size="`small`" :split="false" :data-source="list">
|
|
||||||
<template #renderItem="{ item }">
|
|
||||||
<a-list-item>
|
|
||||||
<a
|
|
||||||
class="ele-text-secondary"
|
|
||||||
@click="openUrl('/cms/article/' + item.articleId)"
|
|
||||||
>
|
|
||||||
{{ item.title }}
|
|
||||||
</a>
|
|
||||||
</a-list-item>
|
|
||||||
</template>
|
|
||||||
</a-list>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { pageArticle } from '@/api/cms/article';
|
|
||||||
import { Article } from '@/api/cms/article/model';
|
|
||||||
import { openNew, openUrl } from '@/utils/common';
|
|
||||||
import { RightOutlined } from '@ant-design/icons-vue';
|
|
||||||
const list = ref<Article[]>([]);
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
title: string;
|
|
||||||
categoryId: number;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载数据
|
|
||||||
*/
|
|
||||||
const reload = () => {
|
|
||||||
const { categoryId } = props;
|
|
||||||
// 加载文章列表
|
|
||||||
pageArticle({ categoryId, limit: 6 }).then((data) => {
|
|
||||||
if (data?.list) {
|
|
||||||
list.value = data.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
reload();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: 'DashboardArticleList'
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card :bordered="false" title="小组成员">
|
|
||||||
<template #extra>
|
|
||||||
<a-tooltip>
|
|
||||||
<template #title>邀请加入</template>
|
|
||||||
<UserAddOutlined @click="onShowQrcode" :style="{ fontSize: '18px' }" />
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
<a-list
|
|
||||||
class="demo-loadmore-list"
|
|
||||||
item-layout="horizontal"
|
|
||||||
:data-source="list"
|
|
||||||
>
|
|
||||||
<template #renderItem="{ item }">
|
|
||||||
<a-list-item>
|
|
||||||
<template #actions>
|
|
||||||
<a-popover>
|
|
||||||
<template #content> 待处理 </template>
|
|
||||||
<a class="ele-text-danger">{{ item.pending }}</a>
|
|
||||||
</a-popover>
|
|
||||||
<a-popover>
|
|
||||||
<template #content> 本月已处理 </template>
|
|
||||||
<a class="ele-text-secondary">{{ item.month }}</a>
|
|
||||||
</a-popover>
|
|
||||||
</template>
|
|
||||||
<a-skeleton avatar :title="false" :loading="!!item.loading" active>
|
|
||||||
<a-list-item-meta>
|
|
||||||
<template #title>
|
|
||||||
{{ item.nickname }}
|
|
||||||
</template>
|
|
||||||
<template #avatar>
|
|
||||||
<a-avatar :src="item.avatar" />
|
|
||||||
</template>
|
|
||||||
</a-list-item-meta>
|
|
||||||
</a-skeleton>
|
|
||||||
</a-list-item>
|
|
||||||
</template>
|
|
||||||
</a-list>
|
|
||||||
<!-- 工单二维码 -->
|
|
||||||
<Qrcode v-model:visible="showQrcode" />
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { pageTaskCount } from '@/api/oa/task-count';
|
|
||||||
import { TaskCount } from '@/api/oa/task-count/model';
|
|
||||||
import { UserAddOutlined } from '@ant-design/icons-vue';
|
|
||||||
import Qrcode from './qrcode.vue';
|
|
||||||
|
|
||||||
const showQrcode = ref(false);
|
|
||||||
const list = ref<TaskCount[]>([]);
|
|
||||||
|
|
||||||
pageTaskCount({ limit: 10, roleCode: 'commander' }).then((res) => {
|
|
||||||
if (res) {
|
|
||||||
list.value = res?.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const onShowQrcode = () => {
|
|
||||||
showQrcode.value = true;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.monitor-evaluate-text {
|
|
||||||
width: 90px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
opacity: 0.8;
|
|
||||||
|
|
||||||
& > .anticon {
|
|
||||||
font-size: 12px;
|
|
||||||
margin: 0 6px 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/deep/.ant-list-item {
|
|
||||||
padding: 7px 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<!-- 本月目标 -->
|
|
||||||
<template>
|
|
||||||
<a-card :title="title" :bordered="false">
|
|
||||||
<template #extra>
|
|
||||||
<more-icon @remove="onRemove" @edit="onEdit" />
|
|
||||||
</template>
|
|
||||||
<div class="workplace-goal-group">
|
|
||||||
<a-progress
|
|
||||||
:width="180"
|
|
||||||
:percent="80"
|
|
||||||
type="dashboard"
|
|
||||||
:stroke-width="4"
|
|
||||||
:show-info="false"
|
|
||||||
/>
|
|
||||||
<div class="workplace-goal-content">
|
|
||||||
<ele-tag color="blue" size="large" shape="circle">
|
|
||||||
<trophy-outlined />
|
|
||||||
</ele-tag>
|
|
||||||
<div class="workplace-goal-num">285</div>
|
|
||||||
</div>
|
|
||||||
<div class="workplace-goal-text">恭喜, 本月目标已达标!</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { TrophyOutlined } from '@ant-design/icons-vue';
|
|
||||||
import MoreIcon from './more-icon.vue';
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
title?: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'remove'): void;
|
|
||||||
(e: 'edit'): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const onRemove = () => {
|
|
||||||
emit('remove');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEdit = () => {
|
|
||||||
emit('edit');
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.workplace-goal-group {
|
|
||||||
height: 310px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.workplace-goal-content {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 180px;
|
|
||||||
margin: -50px 0 0 -90px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-goal-num {
|
|
||||||
font-size: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
<!-- 本月目标 -->
|
|
||||||
<template>
|
|
||||||
<a-card :title="title" :bordered="false">
|
|
||||||
<template #extra>
|
|
||||||
<more-icon @remove="onRemove" @edit="onEdit" />
|
|
||||||
</template>
|
|
||||||
<div class="workplace-goal-group">
|
|
||||||
<a-progress
|
|
||||||
:width="180"
|
|
||||||
:percent="80"
|
|
||||||
type="dashboard"
|
|
||||||
:stroke-width="4"
|
|
||||||
:show-info="false"
|
|
||||||
/>
|
|
||||||
<div class="workplace-goal-content">
|
|
||||||
<ele-tag color="blue" size="large" shape="circle">
|
|
||||||
<trophy-outlined />
|
|
||||||
</ele-tag>
|
|
||||||
<div class="workplace-goal-num">285</div>
|
|
||||||
</div>
|
|
||||||
<div class="workplace-goal-text">恭喜, 本月目标已达标!</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { TrophyOutlined } from '@ant-design/icons-vue';
|
|
||||||
import MoreIcon from './more-icon.vue';
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
title?: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'remove'): void;
|
|
||||||
(e: 'edit'): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const onRemove = () => {
|
|
||||||
emit('remove');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEdit = () => {
|
|
||||||
emit('edit');
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.workplace-goal-group {
|
|
||||||
height: 310px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.workplace-goal-content {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 180px;
|
|
||||||
margin: -50px 0 0 -90px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-goal-num {
|
|
||||||
font-size: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
72
src/views/system/dashboard/components/hot-search.vue
Normal file
72
src/views/system/dashboard/components/hot-search.vue
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<a-card :bordered="false" title="热门搜索">
|
||||||
|
<v-chart
|
||||||
|
ref="hotSearchChartRef"
|
||||||
|
:option="hotSearchChartOption"
|
||||||
|
style="height: 330px"
|
||||||
|
/>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue/es';
|
||||||
|
import { use } from 'echarts/core';
|
||||||
|
import type { EChartsCoreOption } from 'echarts/core';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { LineChart, BarChart } from 'echarts/charts';
|
||||||
|
import { GridComponent, TooltipComponent } from 'echarts/components';
|
||||||
|
import VChart from 'vue-echarts';
|
||||||
|
import 'echarts-wordcloud';
|
||||||
|
import { wordCloudColor } from 'ele-admin-pro/es';
|
||||||
|
import { getWordCloudList } from '@/api/dashboard/analysis';
|
||||||
|
import useEcharts from '@/utils/use-echarts';
|
||||||
|
|
||||||
|
use([CanvasRenderer, LineChart, BarChart, GridComponent, TooltipComponent]);
|
||||||
|
|
||||||
|
//
|
||||||
|
const hotSearchChartRef = ref<InstanceType<typeof VChart> | null>(null);
|
||||||
|
|
||||||
|
useEcharts([hotSearchChartRef]);
|
||||||
|
|
||||||
|
// 词云图表配置
|
||||||
|
const hotSearchChartOption: EChartsCoreOption = reactive({});
|
||||||
|
|
||||||
|
/* 获取词云数据 */
|
||||||
|
const getWordCloudData = () => {
|
||||||
|
getWordCloudList()
|
||||||
|
.then((data) => {
|
||||||
|
Object.assign(hotSearchChartOption, {
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
confine: true,
|
||||||
|
borderWidth: 1
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'wordCloud',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
sizeRange: [12, 24],
|
||||||
|
gridSize: 6,
|
||||||
|
textStyle: {
|
||||||
|
color: wordCloudColor
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
textStyle: {
|
||||||
|
shadowBlur: 8,
|
||||||
|
shadowColor: 'rgba(0, 0, 0, .15)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getWordCloudData();
|
||||||
|
</script>
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
<!-- 快捷方式 -->
|
|
||||||
<template>
|
|
||||||
<a-row :gutter="16" ref="wrapRef">
|
|
||||||
<a-col v-for="item in data" :key="item.url" :lg="3" :md="6" :sm="9" :xs="8">
|
|
||||||
<a-card :bordered="false" hoverable :body-style="{ padding: 0 }">
|
|
||||||
<div class="app-link-block" @click="navTo(item)">
|
|
||||||
<component
|
|
||||||
:is="item.icon"
|
|
||||||
class="app-link-icon"
|
|
||||||
:style="{ color: item.color }"
|
|
||||||
/>
|
|
||||||
<div class="app-link-title">{{ item.title }}</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
|
||||||
import SortableJs from 'sortablejs';
|
|
||||||
import type { Row as ARow } from 'ant-design-vue';
|
|
||||||
import { openUrl } from '@/utils/common';
|
|
||||||
import { getOriginDomain } from '@/utils/domain';
|
|
||||||
const CACHE_KEY = 'workplace-links';
|
|
||||||
// 当前开发环境
|
|
||||||
const env = import.meta.env.MODE;
|
|
||||||
|
|
||||||
interface LinkItem {
|
|
||||||
icon: string;
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
color?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认顺序
|
|
||||||
const DEFAULT: LinkItem[] = [
|
|
||||||
{
|
|
||||||
icon: 'settingOutlined',
|
|
||||||
title: '系统设置',
|
|
||||||
url: '/system/setting'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'AntDesignOutlined',
|
|
||||||
title: '项目管理',
|
|
||||||
url: '/oa/app/index'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'TeamOutlined',
|
|
||||||
title: '用户管理',
|
|
||||||
url: '/system/user'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ShoppingOutlined',
|
|
||||||
title: '产品管理',
|
|
||||||
url: '/product/index'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FileSearchOutlined',
|
|
||||||
title: '文章管理',
|
|
||||||
url: '/cms/article'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'ChromeOutlined',
|
|
||||||
title: '网址导航',
|
|
||||||
url: '/oa/link'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'AppstoreAddOutlined',
|
|
||||||
title: '扩展插件',
|
|
||||||
url: '/system/plug'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'DesktopOutlined',
|
|
||||||
title: '应用主页',
|
|
||||||
url: `http://${localStorage.getItem('TenantId')}.${localStorage.getItem(
|
|
||||||
'domain'
|
|
||||||
)}`
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 获取缓存的顺序
|
|
||||||
const cache = (() => {
|
|
||||||
const str = localStorage.getItem(CACHE_KEY);
|
|
||||||
try {
|
|
||||||
return str ? JSON.parse(str) : null;
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
const data = ref<LinkItem[]>([...(cache ?? DEFAULT)]);
|
|
||||||
|
|
||||||
const wrapRef = ref<InstanceType<typeof ARow> | null>(null);
|
|
||||||
|
|
||||||
let sortableIns: SortableJs | null = null;
|
|
||||||
|
|
||||||
/* 重置布局 */
|
|
||||||
const reset = () => {
|
|
||||||
data.value = [...DEFAULT];
|
|
||||||
cacheData();
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 缓存布局 */
|
|
||||||
const cacheData = () => {
|
|
||||||
localStorage.setItem(CACHE_KEY, JSON.stringify(data.value));
|
|
||||||
};
|
|
||||||
|
|
||||||
const navTo = (item) => {
|
|
||||||
if (item.icon == 'DesktopOutlined') {
|
|
||||||
if (env == 'development') {
|
|
||||||
return openUrl(getOriginDomain());
|
|
||||||
}
|
|
||||||
return openUrl(`http://www.${domain.value}`);
|
|
||||||
}
|
|
||||||
openUrl(item.url);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const isTouchDevice = 'ontouchstart' in document.documentElement;
|
|
||||||
if (isTouchDevice) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sortableIns = new SortableJs(wrapRef.value?.$el, {
|
|
||||||
animation: 300,
|
|
||||||
onUpdate: ({ oldIndex, newIndex }) => {
|
|
||||||
if (typeof oldIndex === 'number' && typeof newIndex === 'number') {
|
|
||||||
const temp = [...data.value];
|
|
||||||
temp.splice(newIndex, 0, temp.splice(oldIndex, 1)[0]);
|
|
||||||
data.value = temp;
|
|
||||||
cacheData();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setData: () => {}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (sortableIns) {
|
|
||||||
sortableIns.destroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
defineExpose({ reset });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import * as icons from './link-icons';
|
|
||||||
import { getSiteInfo } from '@/api/layout';
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
const tenantId = ref<number>();
|
|
||||||
const domain = ref<string>();
|
|
||||||
|
|
||||||
getSiteInfo().then((data) => {
|
|
||||||
tenantId.value = data.tenantId;
|
|
||||||
domain.value = data.domain;
|
|
||||||
});
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: icons
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.app-link-block {
|
|
||||||
padding: 12px;
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
color: inherit;
|
|
||||||
|
|
||||||
.app-link-icon {
|
|
||||||
color: #666666;
|
|
||||||
font-size: 30px;
|
|
||||||
margin: 6px 0 10px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
export {
|
|
||||||
UserOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
FileSearchOutlined,
|
|
||||||
ChromeOutlined,
|
|
||||||
ShoppingOutlined,
|
|
||||||
LaptopOutlined,
|
|
||||||
AppstoreAddOutlined,
|
|
||||||
DesktopOutlined,
|
|
||||||
AntDesignOutlined,
|
|
||||||
SettingOutlined
|
|
||||||
} from '@ant-design/icons-vue';
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card :title="linkType" :bordered="false" :body-style="{ padding: '2px' }">
|
|
||||||
<template #extra
|
|
||||||
><a @click="openNew('/oa/link')" class="ele-text-placeholder"
|
|
||||||
>更多<RightOutlined /></a
|
|
||||||
></template>
|
|
||||||
<a-list :size="`small`" :split="false" :data-source="list">
|
|
||||||
<template #renderItem="{ item }">
|
|
||||||
<a-list-item>
|
|
||||||
<a-list-item-meta>
|
|
||||||
<template #avatar>
|
|
||||||
<a-avatar :src="item.icon" />
|
|
||||||
</template>
|
|
||||||
<template #title>
|
|
||||||
<a @click="openUrl(item.url)">{{ item.name }}</a>
|
|
||||||
</template>
|
|
||||||
</a-list-item-meta>
|
|
||||||
</a-list-item>
|
|
||||||
</template>
|
|
||||||
</a-list>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { openNew, openUrl } from '@/utils/common';
|
|
||||||
import { pageLink } from '@/api/oa/link';
|
|
||||||
import { RightOutlined } from '@ant-design/icons-vue';
|
|
||||||
const list = ref<any[]>([]);
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
linkType: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载数据
|
|
||||||
*/
|
|
||||||
const reload = () => {
|
|
||||||
const { linkType } = props;
|
|
||||||
// 加载文章列表
|
|
||||||
pageLink({ linkType, limit: 5 }).then((data) => {
|
|
||||||
if (data?.list) {
|
|
||||||
list.value = data.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
reload();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: 'DashboardArticleList'
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-dropdown placement="bottomRight">
|
|
||||||
<more-outlined class="ele-text-secondary" style="font-size: 18px" />
|
|
||||||
<template #overlay>
|
|
||||||
<a-menu :selectable="false" @click="onClick">
|
|
||||||
<a-menu-item key="edit">
|
|
||||||
<div class="ele-cell">
|
|
||||||
<edit-outlined />
|
|
||||||
<div class="ele-cell-content">编辑</div>
|
|
||||||
</div>
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item key="remove">
|
|
||||||
<div class="ele-cell ele-text-danger">
|
|
||||||
<delete-outlined />
|
|
||||||
<div class="ele-cell-content">删除</div>
|
|
||||||
</div>
|
|
||||||
</a-menu-item>
|
|
||||||
</a-menu>
|
|
||||||
</template>
|
|
||||||
</a-dropdown>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import {
|
|
||||||
MoreOutlined,
|
|
||||||
EditOutlined,
|
|
||||||
DeleteOutlined
|
|
||||||
} from '@ant-design/icons-vue';
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'edit'): void;
|
|
||||||
(e: 'remove'): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const onClick = ({ key }) => {
|
|
||||||
emit(key);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
<!-- 用户信息 -->
|
|
||||||
<template>
|
|
||||||
<a-card :bordered="false" :body-style="{ padding: '20px' }">
|
|
||||||
<div class="ele-cell workplace-user-card">
|
|
||||||
<div class="ele-cell-content ele-cell">
|
|
||||||
<a-avatar :size="68" :src="loginUser.avatar">
|
|
||||||
<template v-if="!loginUser.avatar" #icon>
|
|
||||||
<user-outlined />
|
|
||||||
</template>
|
|
||||||
</a-avatar>
|
|
||||||
<div class="ele-cell-content">
|
|
||||||
<h4 class="ele-elip">
|
|
||||||
早安, {{ loginUser.nickname }}, 开始您一天的工作吧!
|
|
||||||
</h4>
|
|
||||||
<div class="ele-elip ele-text-secondary">
|
|
||||||
<cloud-outlined />
|
|
||||||
<em>{{ elip[Math.floor(Math.random() * elip.length)] }}</em>
|
|
||||||
<!-- <em>今日多云转阴,18℃ - 22℃,出门记得穿外套哦~</em>-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="workplace-count-group">
|
|
||||||
<!-- <div class="workplace-count-item">-->
|
|
||||||
<!-- <div class="workplace-count-header">-->
|
|
||||||
<!-- <ele-tag color="blue" shape="circle" size="small">-->
|
|
||||||
<!-- <appstore-filled />-->
|
|
||||||
<!-- </ele-tag>-->
|
|
||||||
<!-- <span class="workplace-count-name">项目数</span>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <h2>0</h2>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="workplace-count-item">-->
|
|
||||||
<!-- <div class="workplace-count-header">-->
|
|
||||||
<!-- <ele-tag color="orange" shape="circle" size="small">-->
|
|
||||||
<!-- <check-square-outlined />-->
|
|
||||||
<!-- </ele-tag>-->
|
|
||||||
<!-- <span class="workplace-count-name">待办项</span>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <h2>6 / 24</h2>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="workplace-count-item">-->
|
|
||||||
<!-- <div class="workplace-count-header">-->
|
|
||||||
<!-- <ele-tag color="green" shape="circle" size="small">-->
|
|
||||||
<!-- <bell-filled />-->
|
|
||||||
<!-- </ele-tag>-->
|
|
||||||
<!-- <span class="workplace-count-name">消息</span>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <h2>0</h2>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import {
|
|
||||||
UserOutlined,
|
|
||||||
CloudOutlined,
|
|
||||||
AppstoreFilled,
|
|
||||||
CheckSquareOutlined,
|
|
||||||
BellFilled
|
|
||||||
} from '@ant-design/icons-vue';
|
|
||||||
import { useUserStore } from '@/store/modules/user';
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
|
||||||
|
|
||||||
// 当前登录用户信息
|
|
||||||
const loginUser = computed(() => userStore.info ?? {});
|
|
||||||
const elip = ref<string[]>([
|
|
||||||
'小事成就大事,细节成就完美~',
|
|
||||||
'心态决定命运,自信走向成功',
|
|
||||||
'人生能有几回博,今日不博何时博',
|
|
||||||
'成功需要成本,时间也是一种成本,对时间的珍惜就是对成本的节约',
|
|
||||||
'有志者自有千方百计,无志者只感千难万难',
|
|
||||||
'积一时之跬步,臻千里之遥程'
|
|
||||||
]);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.workplace-user-card {
|
|
||||||
.ele-cell-content {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-count-group {
|
|
||||||
white-space: nowrap;
|
|
||||||
text-align: right;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-count-item {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 4px 0 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-count-name {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 992px) {
|
|
||||||
.workplace-count-item {
|
|
||||||
margin: 0 2px 0 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.workplace-user-card {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-count-group {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ele-modal
|
|
||||||
:width="400"
|
|
||||||
:visible="visible"
|
|
||||||
:title="`邀请新成员`"
|
|
||||||
:body-style="{ paddingBottom: '28px' }"
|
|
||||||
@update:visible="updateVisible"
|
|
||||||
:footer="null"
|
|
||||||
@ok="save"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="qrcode-list"
|
|
||||||
style="display: flex; justify-content: space-around"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<img :src="qrcode" width="240" height="240" />
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 26px;
|
|
||||||
padding-top: 20px;
|
|
||||||
"
|
|
||||||
>使用微信扫一扫</div
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ele-modal>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { User } from '@/api/system/user/model';
|
|
||||||
import { reactive, ref } from 'vue';
|
|
||||||
import { taskJoinQRCode } from '@/api/oa/task';
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
// 弹窗是否打开
|
|
||||||
visible: boolean;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'done', user: User): void;
|
|
||||||
(e: 'update:visible', visible: boolean): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
/* 更新visible */
|
|
||||||
const updateVisible = (value: boolean) => {
|
|
||||||
emit('update:visible', value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const qrcode = ref('');
|
|
||||||
|
|
||||||
// 用户信息
|
|
||||||
const form = reactive<User>({
|
|
||||||
userId: undefined,
|
|
||||||
nickname: undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
const save = () => {
|
|
||||||
emit('done', form);
|
|
||||||
};
|
|
||||||
|
|
||||||
taskJoinQRCode({}).then((text) => {
|
|
||||||
qrcode.value = String(text);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style scoped lang="less"></style>
|
|
||||||
247
src/views/system/dashboard/components/sale-card.vue
Normal file
247
src/views/system/dashboard/components/sale-card.vue
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
<template>
|
||||||
|
<a-card :bordered="false" :body-style="{ padding: 0 }">
|
||||||
|
<a-tabs
|
||||||
|
size="large"
|
||||||
|
v-model:activeKey="saleSearch.type"
|
||||||
|
class="monitor-card-tabs"
|
||||||
|
@change="onSaleTypeChange"
|
||||||
|
>
|
||||||
|
<a-tab-pane tab="销售额" key="saleroom" />
|
||||||
|
<template #rightExtra>
|
||||||
|
<a-space
|
||||||
|
size="middle"
|
||||||
|
:class="[
|
||||||
|
'analysis-tabs-extra',
|
||||||
|
{ 'hidden-lg-and-down': styleResponsive }
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<a-radio-group v-model:value="saleSearch.dateType">
|
||||||
|
<a-radio-button value="1">今天</a-radio-button>
|
||||||
|
<a-radio-button value="2">本周</a-radio-button>
|
||||||
|
<a-radio-button value="3">本月</a-radio-button>
|
||||||
|
<a-radio-button value="4">本年</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
<div style="width: 300px">
|
||||||
|
<a-range-picker
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
v-model:value="saleSearch.datetime"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</a-tabs>
|
||||||
|
<div style="padding-bottom: 10px">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col
|
||||||
|
v-bind="
|
||||||
|
styleResponsive ? { lg: 17, md: 15, sm: 24, xs: 24 } : { span: 17 }
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div v-if="saleSearch.type === 'saleroom'" class="demo-monitor-title">
|
||||||
|
销售量趋势
|
||||||
|
</div>
|
||||||
|
<div v-else class="demo-monitor-title">访问量趋势</div>
|
||||||
|
<v-chart
|
||||||
|
ref="saleChartRef"
|
||||||
|
:option="saleChartOption"
|
||||||
|
style="height: 320px"
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
|
<a-col
|
||||||
|
v-bind="
|
||||||
|
styleResponsive ? { lg: 7, md: 9, sm: 24, xs: 24 } : { span: 7 }
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div v-if="saleSearch.type === 'saleroom'">
|
||||||
|
<div class="demo-monitor-title">门店销售额排名</div>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in saleroomRankData"
|
||||||
|
:key="index"
|
||||||
|
class="demo-monitor-rank-item ele-cell"
|
||||||
|
>
|
||||||
|
<ele-tag
|
||||||
|
shape="circle"
|
||||||
|
:color="index < 3 ? '#314659' : ''"
|
||||||
|
style="border: none"
|
||||||
|
>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</ele-tag>
|
||||||
|
<div class="ele-cell-content ele-elip">{{ item.name }}</div>
|
||||||
|
<div class="ele-text-secondary">{{ item.value }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="demo-monitor-title">门店访问量排名</div>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in visitsRankData"
|
||||||
|
:key="index"
|
||||||
|
class="demo-monitor-rank-item ele-cell"
|
||||||
|
>
|
||||||
|
<ele-tag
|
||||||
|
shape="circle"
|
||||||
|
:color="index < 3 ? '#314659' : ''"
|
||||||
|
style="border: none"
|
||||||
|
>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</ele-tag>
|
||||||
|
<div class="ele-cell-content ele-elip">{{ item.name }}</div>
|
||||||
|
<div class="ele-text-secondary">{{ item.value }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue/es';
|
||||||
|
import { use } from 'echarts/core';
|
||||||
|
import type { EChartsCoreOption } from 'echarts/core';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { BarChart } from 'echarts/charts';
|
||||||
|
import { GridComponent, TooltipComponent } from 'echarts/components';
|
||||||
|
import VChart from 'vue-echarts';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
|
import { getSaleroomList } from '@/api/dashboard/analysis';
|
||||||
|
import type { SaleroomData } from '@/api/dashboard/analysis/model';
|
||||||
|
import useEcharts from '@/utils/use-echarts';
|
||||||
|
|
||||||
|
use([CanvasRenderer, BarChart, GridComponent, TooltipComponent]);
|
||||||
|
|
||||||
|
// 是否开启响应式布局
|
||||||
|
const themeStore = useThemeStore();
|
||||||
|
const { styleResponsive } = storeToRefs(themeStore);
|
||||||
|
|
||||||
|
//
|
||||||
|
const saleChartRef = ref<InstanceType<typeof VChart> | null>(null);
|
||||||
|
|
||||||
|
useEcharts([saleChartRef]);
|
||||||
|
|
||||||
|
// 销售额柱状图配置
|
||||||
|
const saleChartOption: EChartsCoreOption = reactive({});
|
||||||
|
|
||||||
|
// 门店销售排名数据
|
||||||
|
const saleroomRankData = ref([
|
||||||
|
{ name: '工专路 1 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 2 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 3 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 4 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 5 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 6 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 7 号店', value: '323,234' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 门店访问排名数据
|
||||||
|
const visitsRankData = ref([
|
||||||
|
{ name: '工专路 1 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 2 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 3 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 4 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 5 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 6 号店', value: '323,234' },
|
||||||
|
{ name: '工专路 7 号店', value: '323,234' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 销售量趋势数据
|
||||||
|
const saleroomData1 = ref<SaleroomData[]>([]);
|
||||||
|
|
||||||
|
// 访问量趋势数据
|
||||||
|
const saleroomData2 = ref<SaleroomData[]>([]);
|
||||||
|
|
||||||
|
interface SaleSearchType {
|
||||||
|
type: string;
|
||||||
|
dateType: string;
|
||||||
|
datetime: [string, string];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销售量搜索参数
|
||||||
|
const saleSearch = reactive<SaleSearchType>({
|
||||||
|
type: 'saleroom',
|
||||||
|
dateType: '1',
|
||||||
|
datetime: ['2022-01-08', '2022-02-12']
|
||||||
|
});
|
||||||
|
|
||||||
|
/* 获取销售量数据 */
|
||||||
|
const getSaleroomData = () => {
|
||||||
|
getSaleroomList()
|
||||||
|
.then((data) => {
|
||||||
|
saleroomData1.value = data.list1;
|
||||||
|
saleroomData2.value = data.list2;
|
||||||
|
onSaleTypeChange();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 销售量tab选择改变事件 */
|
||||||
|
const onSaleTypeChange = () => {
|
||||||
|
if (saleSearch.type === 'saleroom') {
|
||||||
|
Object.assign(saleChartOption, {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
data: saleroomData1.value.map((d) => d.month)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
data: saleroomData1.value.map((d) => d.value)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Object.assign(saleChartOption, {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
data: saleroomData2.value.map((d) => d.month)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
data: saleroomData2.value.map((d) => d.value)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getSaleroomData();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.monitor-card-tabs :deep(.ant-tabs-nav) {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-monitor-title {
|
||||||
|
padding: 6px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-monitor-rank-item {
|
||||||
|
padding: 0 20px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
246
src/views/system/dashboard/components/statistics-card.vue
Normal file
246
src/views/system/dashboard/components/statistics-card.vue
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
<!-- 统计卡片 -->
|
||||||
|
<template>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col
|
||||||
|
v-bind="styleResponsive ? { lg: 6, md: 12, sm: 24, xs: 24 } : { span: 6 }"
|
||||||
|
>
|
||||||
|
<a-card class="analysis-chart-card" :bordered="false">
|
||||||
|
<div class="ele-text-secondary ele-cell">
|
||||||
|
<div class="ele-cell-content">总销售额</div>
|
||||||
|
<a-tooltip title="指标说明">
|
||||||
|
<question-circle-outlined />
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<h1 class="analysis-chart-card-num">¥ 126,560</h1>
|
||||||
|
<div class="analysis-chart-card-content" style="padding-top: 16px">
|
||||||
|
<a-space size="middle">
|
||||||
|
<span class="analysis-trend-text">
|
||||||
|
周同比12% <caret-up-outlined class="ele-text-danger" />
|
||||||
|
</span>
|
||||||
|
<span class="analysis-trend-text">
|
||||||
|
日同比11% <caret-down-outlined class="ele-text-success" />
|
||||||
|
</span>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
<a-divider />
|
||||||
|
<div>日销售额 ¥12,423</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col
|
||||||
|
v-bind="styleResponsive ? { lg: 6, md: 12, sm: 24, xs: 24 } : { span: 6 }"
|
||||||
|
>
|
||||||
|
<a-card class="analysis-chart-card" :bordered="false">
|
||||||
|
<div class="ele-text-secondary ele-cell">
|
||||||
|
<div class="ele-cell-content">访问量</div>
|
||||||
|
<ele-tag color="red">日</ele-tag>
|
||||||
|
</div>
|
||||||
|
<h1 class="analysis-chart-card-num">8,846</h1>
|
||||||
|
<v-chart
|
||||||
|
ref="visitChartRef"
|
||||||
|
:option="visitChartOption"
|
||||||
|
style="height: 40px"
|
||||||
|
/>
|
||||||
|
<a-divider />
|
||||||
|
<div>日访问量 1,234</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col
|
||||||
|
v-bind="styleResponsive ? { lg: 6, md: 12, sm: 24, xs: 24 } : { span: 6 }"
|
||||||
|
>
|
||||||
|
<a-card class="analysis-chart-card" :bordered="false">
|
||||||
|
<div class="ele-text-secondary ele-cell">
|
||||||
|
<div class="ele-cell-content">支付笔数</div>
|
||||||
|
<ele-tag color="blue">月</ele-tag>
|
||||||
|
</div>
|
||||||
|
<h1 class="analysis-chart-card-num">6,560</h1>
|
||||||
|
<v-chart
|
||||||
|
ref="payNumChartRef"
|
||||||
|
:option="payNumChartOption"
|
||||||
|
style="height: 40px"
|
||||||
|
/>
|
||||||
|
<a-divider />
|
||||||
|
<div>转化率 60%</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col
|
||||||
|
v-bind="styleResponsive ? { lg: 6, md: 12, sm: 24, xs: 24 } : { span: 6 }"
|
||||||
|
>
|
||||||
|
<a-card class="analysis-chart-card" :bordered="false">
|
||||||
|
<div class="ele-text-secondary ele-cell">
|
||||||
|
<div class="ele-cell-content">活动运营效果</div>
|
||||||
|
<ele-tag color="green">周</ele-tag>
|
||||||
|
</div>
|
||||||
|
<h1 class="analysis-chart-card-num">78%</h1>
|
||||||
|
<div class="analysis-chart-card-content" style="padding-top: 16px">
|
||||||
|
<a-progress
|
||||||
|
:percent="78"
|
||||||
|
:show-info="false"
|
||||||
|
stroke-color="#13c2c2"
|
||||||
|
status="active"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<a-divider />
|
||||||
|
<a-space size="middle">
|
||||||
|
<span class="analysis-trend-text">
|
||||||
|
周同比12% <caret-up-outlined class="ele-text-danger" />
|
||||||
|
</span>
|
||||||
|
<span class="analysis-trend-text">
|
||||||
|
日同比11% <caret-down-outlined class="ele-text-success" />
|
||||||
|
</span>
|
||||||
|
</a-space>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue/es';
|
||||||
|
import {
|
||||||
|
QuestionCircleOutlined,
|
||||||
|
CaretUpOutlined,
|
||||||
|
CaretDownOutlined
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
import { use } from 'echarts/core';
|
||||||
|
import type { EChartsCoreOption } from 'echarts/core';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { LineChart, BarChart } from 'echarts/charts';
|
||||||
|
import { GridComponent, TooltipComponent } from 'echarts/components';
|
||||||
|
import VChart from 'vue-echarts';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
|
import { getPayNumList } from '@/api/dashboard/analysis';
|
||||||
|
import useEcharts from '@/utils/use-echarts';
|
||||||
|
|
||||||
|
use([CanvasRenderer, LineChart, BarChart, GridComponent, TooltipComponent]);
|
||||||
|
|
||||||
|
// 是否开启响应式布局
|
||||||
|
const themeStore = useThemeStore();
|
||||||
|
const { styleResponsive } = storeToRefs(themeStore);
|
||||||
|
|
||||||
|
//
|
||||||
|
const visitChartRef = ref<InstanceType<typeof VChart> | null>(null);
|
||||||
|
const payNumChartRef = ref<InstanceType<typeof VChart> | null>(null);
|
||||||
|
|
||||||
|
useEcharts([visitChartRef, payNumChartRef]);
|
||||||
|
|
||||||
|
// 访问量折线图配置
|
||||||
|
const visitChartOption: EChartsCoreOption = reactive({});
|
||||||
|
|
||||||
|
// 支付笔数柱状图配置
|
||||||
|
const payNumChartOption: EChartsCoreOption = reactive({});
|
||||||
|
|
||||||
|
/* 获取支付笔数数据 */
|
||||||
|
const getPayNumData = () => {
|
||||||
|
getPayNumList()
|
||||||
|
.then((data) => {
|
||||||
|
Object.assign(visitChartOption, {
|
||||||
|
color: '#975fe5',
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter:
|
||||||
|
'<i class="ele-chart-dot" style="background: #975fe5;"></i>{b0}: {c0}'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 10,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
show: false,
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: data.map((d) => d.date)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
show: false,
|
||||||
|
type: 'value',
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.5
|
||||||
|
},
|
||||||
|
data: data.map((d) => d.value)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.assign(payNumChartOption, {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter:
|
||||||
|
'<i class="ele-chart-dot" style="background: #5b8ff9;"></i>{b0}: {c0}'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 10,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
show: false,
|
||||||
|
type: 'category',
|
||||||
|
data: data.map((d) => d.date)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
show: false,
|
||||||
|
type: 'value',
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
data: data.map((d) => d.value)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getPayNumData();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.analysis-chart-card {
|
||||||
|
:deep(.ant-card-body) {
|
||||||
|
padding: 16px 22px 12px 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-divider) {
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-chart-card-num {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-chart-card-content {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-trend-text {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-card :title="title" :bordered="false" :body-style="{ padding: '2px' }">
|
|
||||||
<template #extra
|
|
||||||
><a @click="openUrl('/oa/task')" class="ele-text-placeholder"
|
|
||||||
>更多<RightOutlined /></a
|
|
||||||
></template>
|
|
||||||
<a-list :size="`small`" :split="false" :data-source="list">
|
|
||||||
<template #renderItem="{ item }">
|
|
||||||
<a-list-item>
|
|
||||||
<div class="app-box">
|
|
||||||
<div class="app-info">
|
|
||||||
<a
|
|
||||||
class="ele-text-secondary"
|
|
||||||
@click="openNew('/oa/task/detail/' + item.taskId)"
|
|
||||||
>
|
|
||||||
<a-typography-paragraph
|
|
||||||
ellipsis
|
|
||||||
:content="`【${item.taskType}】${item.name}`"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<a class="ele-text-placeholder">
|
|
||||||
<a-tag v-if="item.progress === TOBEARRANGED" color="red"
|
|
||||||
>待安排</a-tag
|
|
||||||
>
|
|
||||||
<a-tag v-if="item.progress === PENDING" color="orange"
|
|
||||||
>待处理</a-tag
|
|
||||||
>
|
|
||||||
<a-tag v-if="item.progress === PROCESSING" color="purple"
|
|
||||||
>处理中</a-tag
|
|
||||||
>
|
|
||||||
<a-tag v-if="item.progress === TOBECONFIRMED" color="cyan"
|
|
||||||
>待评价</a-tag
|
|
||||||
>
|
|
||||||
<a-tag v-if="item.progress === COMPLETED" color="green"
|
|
||||||
>已完成</a-tag
|
|
||||||
>
|
|
||||||
<a-tag v-if="item.progress === CLOSED">已关闭</a-tag>
|
|
||||||
<div class="ele-text-danger" v-if="item.overdueDays">
|
|
||||||
已逾期{{ item.overdueDays }}天
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</a-list-item>
|
|
||||||
</template>
|
|
||||||
</a-list>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { openUrl } from '@/utils/common';
|
|
||||||
import { Task } from '@/api/oa/task/model';
|
|
||||||
import { pageTask } from '@/api/oa/task';
|
|
||||||
import { useUserStore } from '@/store/modules/user';
|
|
||||||
import {
|
|
||||||
CLOSED,
|
|
||||||
COMPLETED,
|
|
||||||
PENDING,
|
|
||||||
PROCESSING,
|
|
||||||
TOBEARRANGED,
|
|
||||||
TOBECONFIRMED
|
|
||||||
} from '@/api/oa/task/model/progress';
|
|
||||||
import { RightOutlined } from '@ant-design/icons-vue';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
title: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const list = ref<Task[]>([]);
|
|
||||||
/**
|
|
||||||
* 加载数据
|
|
||||||
*/
|
|
||||||
const reload = () => {
|
|
||||||
const { title } = props;
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const where = {
|
|
||||||
userId: undefined,
|
|
||||||
commander: userStore.info?.userId,
|
|
||||||
limit: 6,
|
|
||||||
status: 0
|
|
||||||
};
|
|
||||||
// 加载列表
|
|
||||||
pageTask(where).then((data) => {
|
|
||||||
if (data?.list) {
|
|
||||||
list.value = data.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
reload();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: 'DashboardArticleList'
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.app-box {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
overflow: hidden;
|
|
||||||
.app-info {
|
|
||||||
display: flex;
|
|
||||||
margin-left: 5px;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 400px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
<!-- 小组成员 -->
|
|
||||||
<template>
|
|
||||||
<a-card :title="title" :bordered="false" :body-style="{ padding: '2px 0px' }">
|
|
||||||
<template #extra>
|
|
||||||
<more-icon @remove="onRemove" @edit="onEdit" />
|
|
||||||
</template>
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in userList"
|
|
||||||
:key="index"
|
|
||||||
class="ele-cell user-list-item"
|
|
||||||
>
|
|
||||||
<div style="flex-shrink: 0">
|
|
||||||
<a-avatar :size="46" :src="item.avatar" />
|
|
||||||
</div>
|
|
||||||
<div class="ele-cell-content">
|
|
||||||
<span class="ele-cell-title ele-elip">{{ item.nickname }}</span>
|
|
||||||
<div class="ele-cell-desc ele-elip">{{ item.phone }}</div>
|
|
||||||
</div>
|
|
||||||
<div style="flex-shrink: 0">
|
|
||||||
<a-tag :color="['green', 'red'][item.status]">
|
|
||||||
{{ ['在线', '离线'][item.status] }}
|
|
||||||
</a-tag>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import MoreIcon from './more-icon.vue';
|
|
||||||
import { pageUsers } from '@/api/system/user';
|
|
||||||
import type { User } from '@/api/system/user/model';
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
title?: string;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'remove'): void;
|
|
||||||
(e: 'edit'): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
// 小组成员数据
|
|
||||||
const userList = ref<User[]>([]);
|
|
||||||
|
|
||||||
/* 查询小组成员 */
|
|
||||||
const queryUserList = () => {
|
|
||||||
pageUsers({ parentId: 11, limit: 5 }).then((data: any) => {
|
|
||||||
userList.value = data.list;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onRemove = () => {
|
|
||||||
emit('remove');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onEdit = () => {
|
|
||||||
emit('edit');
|
|
||||||
};
|
|
||||||
|
|
||||||
queryUserList();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.user-list-item {
|
|
||||||
padding: 12px 18px;
|
|
||||||
|
|
||||||
& + .user-list-item {
|
|
||||||
border-top: 1px solid hsla(0, 0%, 60%, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ele-cell-content {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ele-cell-desc {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-tag {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
101
src/views/system/dashboard/components/visit-hour.vue
Normal file
101
src/views/system/dashboard/components/visit-hour.vue
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<a-card
|
||||||
|
:bordered="false"
|
||||||
|
title="最近1小时访问情况"
|
||||||
|
:body-style="{ padding: '16px 6px 0 0' }"
|
||||||
|
>
|
||||||
|
<v-chart
|
||||||
|
ref="visitHourChartRef"
|
||||||
|
:option="visitHourChartOption"
|
||||||
|
style="height: 362px"
|
||||||
|
/>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue/es';
|
||||||
|
import { use } from 'echarts/core';
|
||||||
|
import type { EChartsCoreOption } from 'echarts/core';
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
import { LineChart } from 'echarts/charts';
|
||||||
|
import {
|
||||||
|
GridComponent,
|
||||||
|
TooltipComponent,
|
||||||
|
LegendComponent
|
||||||
|
} from 'echarts/components';
|
||||||
|
import VChart from 'vue-echarts';
|
||||||
|
import { getVisitHourList } from '@/api/dashboard/analysis';
|
||||||
|
import useEcharts from '@/utils/use-echarts';
|
||||||
|
|
||||||
|
use([
|
||||||
|
CanvasRenderer,
|
||||||
|
LineChart,
|
||||||
|
GridComponent,
|
||||||
|
TooltipComponent,
|
||||||
|
LegendComponent
|
||||||
|
]);
|
||||||
|
|
||||||
|
//
|
||||||
|
const visitHourChartRef = ref<InstanceType<typeof VChart> | null>(null);
|
||||||
|
|
||||||
|
useEcharts([visitHourChartRef]);
|
||||||
|
|
||||||
|
// 最近 1 小时访问情况折线图配置
|
||||||
|
const visitHourChartOption: EChartsCoreOption = reactive({});
|
||||||
|
|
||||||
|
/* 获取最近 1 小时访问情况数据 */
|
||||||
|
const getVisitHourData = () => {
|
||||||
|
getVisitHourList()
|
||||||
|
.then((data) => {
|
||||||
|
Object.assign(visitHourChartOption, {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['浏览量', '访问量'],
|
||||||
|
right: 20
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: data.map((d) => d.time)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '浏览量',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.5
|
||||||
|
},
|
||||||
|
data: data.map((d) => d.views)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '访问量',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.5
|
||||||
|
},
|
||||||
|
data: data.map((d) => d.visits)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
message.error(e.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getVisitHourData();
|
||||||
|
</script>
|
||||||
@@ -1,359 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ele-body ele-body-card">
|
<div class="ele-body ele-body-card">
|
||||||
<a-card :bordered="false">
|
<statistics-card />
|
||||||
<template #title>
|
<sale-card />
|
||||||
<SoundOutlined class="ele-text-danger" />
|
|
||||||
<span class="gg-title ele-text-heading">公告</span>
|
|
||||||
<a @click="openNew('/cms/article/374')" class="ele-text-heading"
|
|
||||||
>系统内测中,如何获取体验账号?</a
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<template #extra>
|
|
||||||
<a @click="openNew('/cms/category/92')" class="ele-text-placeholder"
|
|
||||||
>更多<RightOutlined
|
|
||||||
/></a>
|
|
||||||
</template>
|
|
||||||
</a-card>
|
|
||||||
<!-- <profile-card />-->
|
|
||||||
<LinkCard />
|
|
||||||
<a-row :gutter="16" ref="wrapRef">
|
|
||||||
<a-col :md="9">
|
|
||||||
<App title="我的项目" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :md="9">
|
|
||||||
<Task title="我的工单" :categoryId="92" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :md="6">
|
|
||||||
<Article title="通知公告" :categoryId="92" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :md="6">
|
|
||||||
<Article title="公司动态" :categoryId="37" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :md="6">
|
|
||||||
<Article title="经验分享" :categoryId="93" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :md="6">
|
|
||||||
<Article title="API文档" :categoryId="90" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :md="6">
|
|
||||||
<Link linkType="实用工具" />
|
|
||||||
</a-col>
|
|
||||||
<!-- <a-col :md="12">-->
|
|
||||||
<!-- <a-card title="商品管理" :bordered="false" />-->
|
|
||||||
<!-- </a-col>-->
|
|
||||||
</a-row>
|
|
||||||
<!-- <a-row :gutter="16" ref="wrapRef">-->
|
|
||||||
<!-- <a-col-->
|
|
||||||
<!-- v-for="(item, index) in data"-->
|
|
||||||
<!-- :key="item.name"-->
|
|
||||||
<!-- :lg="item.lg"-->
|
|
||||||
<!-- :md="item.md"-->
|
|
||||||
<!-- :sm="item.sm"-->
|
|
||||||
<!-- :xs="item.xs"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <component-->
|
|
||||||
<!-- :is="item.name"-->
|
|
||||||
<!-- :title="item.title"-->
|
|
||||||
<!-- @remove="onRemove(index)"-->
|
|
||||||
<!-- @edit="onEdit(index)"-->
|
|
||||||
<!-- />-->
|
|
||||||
<!-- </a-col>-->
|
|
||||||
<!-- </a-row>-->
|
|
||||||
<a-card :bordered="false" :body-style="{ padding: 0 }">
|
|
||||||
<div class="ele-cell" style="line-height: 42px">
|
|
||||||
<div
|
|
||||||
class="ele-cell-content ele-text-primary workplace-bottom-btn"
|
|
||||||
@click="add"
|
|
||||||
>
|
|
||||||
<PlusCircleOutlined /> 添加视图
|
|
||||||
</div>
|
|
||||||
<a-divider type="vertical" />
|
|
||||||
<div
|
|
||||||
class="ele-cell-content ele-text-primary workplace-bottom-btn"
|
|
||||||
@click="reset"
|
|
||||||
>
|
|
||||||
<UndoOutlined /> 重置布局
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
<ele-modal
|
|
||||||
:width="680"
|
|
||||||
v-model:visible="visible"
|
|
||||||
title="未添加的视图"
|
|
||||||
:footer="null"
|
|
||||||
>
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col
|
|
||||||
v-for="item in notAddedData"
|
|
||||||
:key="item.name"
|
|
||||||
:md="8"
|
|
||||||
:sm="12"
|
|
||||||
:xs="24"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="workplace-card-item ele-border-split"
|
|
||||||
@click="addView(item)"
|
|
||||||
>
|
|
||||||
<div class="workplace-card-header ele-border-split">
|
|
||||||
{{ item.title }}
|
|
||||||
</div>
|
|
||||||
<div class="workplace-card-body ele-text-placeholder">
|
|
||||||
<plus-circle-outlined />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
<a-empty v-if="!notAddedData.length" description="已添加所有视图" />
|
|
||||||
</ele-modal>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
|
import { storeToRefs } from 'pinia';
|
||||||
import SortableJs from 'sortablejs';
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
import type { Row as ARow } from 'ant-design-vue';
|
import StatisticsCard from './components/statistics-card.vue';
|
||||||
import { message } from 'ant-design-vue';
|
import SaleCard from './components/sale-card.vue';
|
||||||
import Article from './components/article-list.vue';
|
import VisitHour from './components/visit-hour.vue';
|
||||||
import Link from './components/link-list.vue';
|
import HotSearch from './components/hot-search.vue';
|
||||||
import App from './components/app-list.vue';
|
|
||||||
import Task from './components/task-card.vue';
|
|
||||||
import {
|
|
||||||
PlusCircleOutlined,
|
|
||||||
SoundOutlined,
|
|
||||||
RightOutlined
|
|
||||||
} from '@ant-design/icons-vue';
|
|
||||||
import { openNew } from '@/utils/common';
|
|
||||||
const CACHE_KEY = 'workplace-layout';
|
|
||||||
|
|
||||||
interface ViewItem {
|
// 是否开启响应式布局
|
||||||
name: string;
|
const themeStore = useThemeStore();
|
||||||
title: string;
|
const { styleResponsive } = storeToRefs(themeStore);
|
||||||
lg: number;
|
|
||||||
md: number;
|
|
||||||
sm: number;
|
|
||||||
xs: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认布局
|
|
||||||
const DEFAULT: ViewItem[] = [
|
|
||||||
{
|
|
||||||
name: 'link',
|
|
||||||
title: '网址导航',
|
|
||||||
lg: 24,
|
|
||||||
md: 24,
|
|
||||||
sm: 24,
|
|
||||||
xs: 24
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'task-card',
|
|
||||||
title: '我的工单',
|
|
||||||
lg: 18,
|
|
||||||
md: 24,
|
|
||||||
sm: 24,
|
|
||||||
xs: 24
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// name: 'project-card',
|
|
||||||
// title: '项目管理',
|
|
||||||
// lg: 16,
|
|
||||||
// md: 24,
|
|
||||||
// sm: 24,
|
|
||||||
// xs: 24
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
name: 'user-list',
|
|
||||||
title: '小组成员',
|
|
||||||
lg: 6,
|
|
||||||
md: 24,
|
|
||||||
sm: 24,
|
|
||||||
xs: 24
|
|
||||||
}
|
|
||||||
// {
|
|
||||||
// name: 'activities-card',
|
|
||||||
// title: '最新动态',
|
|
||||||
// lg: 6,
|
|
||||||
// md: 24,
|
|
||||||
// sm: 24,
|
|
||||||
// xs: 24
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'goal-card',
|
|
||||||
// title: '本月目标',
|
|
||||||
// lg: 8,
|
|
||||||
// md: 24,
|
|
||||||
// sm: 24,
|
|
||||||
// xs: 24
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'docs',
|
|
||||||
// title: '知识库',
|
|
||||||
// lg: 8,
|
|
||||||
// md: 24,
|
|
||||||
// sm: 24,
|
|
||||||
// xs: 24
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
// 获取缓存的顺序
|
|
||||||
const cache = (() => {
|
|
||||||
const str = localStorage.getItem(CACHE_KEY);
|
|
||||||
try {
|
|
||||||
return str ? JSON.parse(str) : null;
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
const data = ref<ViewItem[]>([...(cache ?? DEFAULT)]);
|
|
||||||
|
|
||||||
const visible = ref(false);
|
|
||||||
|
|
||||||
const wrapRef = ref<InstanceType<typeof ARow> | null>(null);
|
|
||||||
|
|
||||||
let sortableIns: SortableJs | null = null;
|
|
||||||
|
|
||||||
// 未添加的数据
|
|
||||||
const notAddedData = computed(() => {
|
|
||||||
return DEFAULT.filter((d) => !data.value.some((t) => t.name === d.name));
|
|
||||||
});
|
|
||||||
|
|
||||||
/* 添加 */
|
|
||||||
const add = () => {
|
|
||||||
visible.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 重置布局 */
|
|
||||||
const reset = () => {
|
|
||||||
data.value = [...DEFAULT];
|
|
||||||
cacheData();
|
|
||||||
message.success('已重置');
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 缓存布局 */
|
|
||||||
const cacheData = () => {
|
|
||||||
localStorage.setItem(CACHE_KEY, JSON.stringify(data.value));
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 删除视图 */
|
|
||||||
const onRemove = (index: number) => {
|
|
||||||
data.value = data.value.filter((_d, i) => i !== index);
|
|
||||||
cacheData();
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 编辑视图 */
|
|
||||||
const onEdit = (index: number) => {
|
|
||||||
data.value.map((d) => {
|
|
||||||
if (d.name == 'user-list') {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// message.info('点击了编辑');
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 添加视图 */
|
|
||||||
const addView = (item) => {
|
|
||||||
data.value.push(item);
|
|
||||||
cacheData();
|
|
||||||
message.success('已添加');
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const isTouchDevice = 'ontouchstart' in document.documentElement;
|
|
||||||
if (isTouchDevice) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sortableIns = new SortableJs(wrapRef.value?.$el, {
|
|
||||||
handle: '.ant-card-head',
|
|
||||||
animation: 300,
|
|
||||||
onUpdate: ({ oldIndex, newIndex }) => {
|
|
||||||
if (typeof oldIndex === 'number' && typeof newIndex === 'number') {
|
|
||||||
const temp = [...data.value];
|
|
||||||
temp.splice(newIndex, 0, temp.splice(oldIndex, 1)[0]);
|
|
||||||
data.value = temp;
|
|
||||||
cacheData();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setData: () => {}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (sortableIns) {
|
|
||||||
sortableIns.destroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ActivitiesCard from './components/activities-card.vue';
|
|
||||||
import TaskCard from './components/task-card.vue';
|
|
||||||
import GoalCard from './components/goal-card.vue';
|
|
||||||
import UserList from './components/count-user.vue';
|
|
||||||
import Docs from './components/docs.vue';
|
|
||||||
import LinkCard from './components/link-card.vue';
|
|
||||||
import ProfileCard from './components/profile-card.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DashboardWorkplace',
|
name: 'DashboardAnalysis'
|
||||||
components: {
|
|
||||||
LinkCard,
|
|
||||||
UserList,
|
|
||||||
ActivitiesCard,
|
|
||||||
TaskCard,
|
|
||||||
GoalCard,
|
|
||||||
Docs,
|
|
||||||
ProfileCard
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.ele-body :deep(.ant-card-head) {
|
|
||||||
cursor: move;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ele-body :deep(.ant-row > .ant-col.sortable-chosen > .ant-card) {
|
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-bottom-btn {
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-bottom-btn:hover {
|
|
||||||
background: hsla(0, 0%, 60%, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 添加弹窗 */
|
|
||||||
.workplace-card-item {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 4px;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: box-shadow 0.2s, background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-card-item:hover {
|
|
||||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
background: hsla(0, 0%, 60%, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.workplace-card-item .workplace-card-header {
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
border-bottom-style: solid;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
.gg-title {
|
|
||||||
padding: 0 5px;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
.workplace-card-body {
|
|
||||||
font-size: 26px;
|
|
||||||
padding: 24px 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user