Skip to content

Commit

Permalink
feat: add api
Browse files Browse the repository at this point in the history
增加服务器 mock 数据

完善本地数据请求方式
  • Loading branch information
rayadaschn committed Oct 7, 2023
1 parent ebd18bf commit 33ff914
Show file tree
Hide file tree
Showing 33 changed files with 311 additions and 183 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"Attributify",
"ctitle",
"devapi",
"ERRMESSAGE",
"mockjs",
"unocss",
"unplugin",
Expand Down
2 changes: 1 addition & 1 deletion config/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ VITE_DEPLOY_BASE_URL=/survey-sage/

# 接口的网关地址
# 用于 axios 的拦截器动态拼接接口 URL
VITE_API_BASE_URL=/devapi/v1/
VITE_API_BASE_URL=http://198.18.1.185:3001

# 本地存储前缀
VITE_STORAGE_PREFIX=survey-dev
2 changes: 1 addition & 1 deletion config/.env.prod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ VITE_DEPLOY_BASE_URL=/survey-sage/

# 接口的网关地址
# 用于 axios 的拦截器动态拼接接口 URL
VITE_API_BASE_URL=/
VITE_API_BASE_URL=http://198.18.1.185:3001/

# 本地存储前缀
VITE_STORAGE_PREFIX=survey-prod
4 changes: 4 additions & 0 deletions mock/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const Koa = require('koa')
const Router = require('koa-router')
const cors = require('koa2-cors') // 引入 koa2-cors 中间件
const mockList = require('./services/index')

const app = new Koa()
Expand All @@ -14,6 +15,9 @@ async function getRes(fn, ctx) {
})
}

// 使用 CORS 中间件来允许跨域请求
app.use(cors())

// 注册 mock 路由
mockList.forEach((item) => {
const { url, method, response } = item
Expand Down
18 changes: 16 additions & 2 deletions mock/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion mock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
"dependencies": {
"koa": "^2.14.1",
"koa-router": "^12.0.0",
"koa2-cors": "^2.0.6",
"mockjs": "^1.1.0"
},
"devDependencies": {
"nodemon": "^2.0.20"
}
}
}
105 changes: 105 additions & 0 deletions src/api/ajax.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { message } from 'antd'
import axios from 'axios'
import { getToken } from '@/utils'
import type { AxiosError, AxiosResponse } from 'axios'
import { API_BASE_URL } from '@/constant'

/**
* @description: 响应结果
* @argument SUCCESS 请求成功
* @argument EXPIRE token请求失效或校验失败
* @argument ERROR 请求错误
* @argument TIMEOUT 请求超时
* @argument TYPE 请求类型
*/
enum ResultEnum {
SUCCESS = 200,
EXPIRE = 203,
ERROR = -1,
ERRMESSAGE = '请求失败',
TIMEOUT = 25000,
TYPE = 'success',
}
console.log('API_BASE_URL', API_BASE_URL)

const instance = axios.create({
timeout: 10 * 1000,
baseURL: API_BASE_URL,
})

/**
* @description: 请求拦截器
* @returns {*}
*/
instance.interceptors.request.use(
(config) => {
config.headers['Authorization'] = `Bearer ${getToken()}` // JWT 的固定格式
return config
},
(error: AxiosError) => {
message.error(error.message)
return Promise.reject(error)
},
)

/**
* @description: 响应拦截器
* @returns {*}
*/
instance.interceptors.response.use(
(response: AxiosResponse) => {
const resData = (response.data || {}) as ResType
const { errno, data, msg } = resData

// * 登陆失效(code == 203)
if (errno === ResultEnum.EXPIRE) {
// TODO: 清除本地缓存
message.error(msg || ResultEnum.ERRMESSAGE)
// 返回登录页
return Promise.reject(data)
}

if (errno !== ResultEnum.SUCCESS) {
message.error(msg || ResultEnum.ERRMESSAGE)
return Promise.reject(data)
}
return data as any
},
(error: AxiosError) => {
// 处理 HTTP 网络错误
let messageStr = ''
// HTTP 状态码
const status = error.response?.status
switch (status) {
case 401:
messageStr = 'token 失效,请重新登录'
break
case 403:
messageStr = '拒绝访问'
break
case 404:
messageStr = '请求地址错误'
break
case 500:
messageStr = '服务器故障'
break
default:
messageStr = '网络连接故障'
}

message.error(messageStr)
return Promise.reject(error)
},
)

export default instance

export type ResType = {
errno: number
data?: ResDataType
msg?: string
}

export type ResDataType = {
[key: string]: any
}
3 changes: 3 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './question'
export * from './stat'
export * from './user'
28 changes: 28 additions & 0 deletions src/services/question.ts → src/api/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,31 @@ export async function getQuestionListService(
const data = (await axios.get(url, { params: opt })) as ResDataType
return data
}

/** 更新单个问卷 */
export async function updateQuestionService(
id: string,
opt: { [key: string]: any },
): Promise<ResDataType> {
const url = `/api/question/${id}`
const data = (await axios.patch(url, opt)) as ResDataType
return data
}

// 复制问卷
export async function duplicateQuestionService(
id: string,
): Promise<ResDataType> {
const url = `/api/question/duplicate/${id}`
const data = (await axios.post(url)) as ResDataType
return data
}

// 批量彻底删除
export async function deleteQuestionsService(
ids: string[],
): Promise<ResDataType> {
const url = '/api/question'
const data = (await axios.delete(url, { data: { ids } })) as ResDataType
return data
}
21 changes: 21 additions & 0 deletions src/api/stat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import axios, { ResDataType } from './ajax'

// 获取问卷的统计列表
export async function getQuestionStatListService(
questionId: string,
opt: { page: number; pageSize: number },
): Promise<ResDataType> {
const url = `/api/stat/${questionId}`
const data = (await axios.get(url, { params: opt })) as ResDataType
return data
}

// 获取组件统计数据汇总
export async function getComponentStatService(
questionId: string,
componentId: string,
): Promise<ResDataType> {
const url = `/api/stat/${questionId}/${componentId}`
const data = (await axios.get(url)) as ResDataType
return data
}
31 changes: 31 additions & 0 deletions src/api/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import axios, { ResDataType } from './ajax'

// 获取用户信息
export async function getUserInfoService(): Promise<ResDataType> {
const url = '/api/user/info'
const data = (await axios.get(url)) as ResDataType
return data
}

// 注册用户
export async function registerService(
username: string,
password: string,
nickname?: string,
): Promise<ResDataType> {
const url = '/api/user/register'
const body = { username, password, nickname: nickname || username }
const data = (await axios.post(url, body)) as ResDataType
return data
}

// 登录
export async function loginService(
username: string,
password: string,
): Promise<ResDataType> {
const url = '/api/user/login'
const body = { username, password }
const data = (await axios.post(url, body)) as ResDataType
return data
}
2 changes: 1 addition & 1 deletion src/components/Logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { Title } = Typography

const Logo: FC = () => {
return (
<div className={styles.container}>
<div>
<Link to="/">
<Space>
<Title>
Expand Down
29 changes: 20 additions & 9 deletions src/components/QuestionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ const QuestionCard: FC<PropsType> = (props: PropsType) => {
}

return (
<div className={styles.container}>
<div className={styles.title}>
<div className={styles.left}>
<div className="mb-2.5 border-rounded bg-white p-3 transition-transform hover:scale-105 hover:transform hover:shadow-md">
<div className="flex">
<div className="flex-1">
<Link
to={isPublished ? `/question/stat/${id}` : `/question/edit/${id}`}
>
Expand All @@ -55,7 +55,7 @@ const QuestionCard: FC<PropsType> = (props: PropsType) => {
</Link>
</div>

<div className={styles.right}>
<div className="flex-1 text-center font-size-3">
<Space>
{isPublished ? (
<Tag color="processing">已发布</Tag>
Expand All @@ -70,8 +70,8 @@ const QuestionCard: FC<PropsType> = (props: PropsType) => {

<Divider className="m-3" />

<div className={styles['button-container']}>
<div className={styles.left}>
<div className="flex">
<div className="flex-1">
<Space>
<Button
icon={<EditOutlined />}
Expand All @@ -91,9 +91,14 @@ const QuestionCard: FC<PropsType> = (props: PropsType) => {
</Button>
</Space>
</div>
<div className={styles.right}>
<div className="flex-1 text-center">
<Space>
<Button type="text" icon={<StarOutlined />} size="small">
<Button
type="text"
icon={<StarOutlined />}
color="#999"
size="small"
>
标星
</Button>
<Popconfirm
Expand All @@ -102,7 +107,12 @@ const QuestionCard: FC<PropsType> = (props: PropsType) => {
cancelText="取消"
onConfirm={onHandleCopy}
>
<Button type="text" icon={<CopyOutlined />} size="small">
<Button
type="text"
icon={<CopyOutlined />}
color="#999"
size="small"
>
复制
</Button>
</Popconfirm>
Expand All @@ -111,6 +121,7 @@ const QuestionCard: FC<PropsType> = (props: PropsType) => {
type="text"
icon={<DeleteOutlined />}
size="small"
color="#999"
onClick={onHandleDel}
>
删除
Expand Down
12 changes: 11 additions & 1 deletion src/constant/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,14 @@ export const LIST_SEARCH_PARAM_KEY = 'keyword'
export const LIST_PAGE_PARAM_KEY = 'page'
export const LIST_PAGE_SIZE_PARAM_KEY = 'pageSize'

export const LIST_PAGE_SIZE = 10
export const LIST_PAGE_SIZE = 10 // 默认的 pageSize
export const STAT_PAGE_SIZE = 10 // 统计列表,默认的 pageSize

export const STAT_COLORS = [
'#FF2D2D',
'#BE77FF',
'#2894FF',
'#00EC00',
'#EAC100',
'#FF9D6F',
]
Loading

0 comments on commit 33ff914

Please sign in to comment.