- 做了什么: - 新增客服手动录单数据库迁移 000084 及对应模型,支持编号唯一校验、客服快照绑定与 CRUD 操作; - 后端提供 csmanualentry 业务模块及相关 API,并在仪表盘摘要中聚合今日各客服录单数量; - 前端增加客服手动录单视图页面、路由与侧边栏导航,支持录单二次确认与细粒度权限控制; - 管理后台仪表盘增加今日客服手动录单卡片展示。 - 为什么: - 满足客服在后台手动登记外部业务编号需求,并便于运营按客服统计今日录单业绩和追溯对账。 - 验证方式: - 执行后端全量测试 go test ./... 与静态检查 go vet ./... 全部通过; - 执行前端代码门禁 npm run check 与 vite build 全部通过; - 执行 goose down/up 迁移回滚与应用测试通过,角色权限分配正确; - 本地 dev 联调 POST /api/admin/manual-entries 录单成功返回 201。
82 lines
1.8 KiB
TypeScript
82 lines
1.8 KiB
TypeScript
import { apiClient } from '@/shared/api/client'
|
|
|
|
import type { ApiResponse, PaginatedResult } from '@/shared/types/types'
|
|
|
|
export interface ManualEntryItem {
|
|
id: number
|
|
entry_no: string
|
|
admin_id: number
|
|
admin_name: string
|
|
admin_username: string
|
|
remark: string
|
|
created_at: string
|
|
}
|
|
|
|
export interface ManualEntryAgentStats {
|
|
admin_id: number
|
|
admin_name: string
|
|
count: number
|
|
}
|
|
|
|
export interface CreateManualEntryRequest {
|
|
entry_no: string
|
|
remark?: string
|
|
}
|
|
|
|
export interface UpdateManualEntryRequest {
|
|
entry_no: string
|
|
remark?: string
|
|
}
|
|
|
|
export interface ManualEntryListQuery {
|
|
entry_no?: string
|
|
keyword?: string
|
|
admin_id?: number
|
|
start_date?: string
|
|
end_date?: string
|
|
}
|
|
|
|
export async function fetchManualEntries(
|
|
page = 1,
|
|
pageSize = 20,
|
|
query: ManualEntryListQuery = {}
|
|
) {
|
|
const { data } = await apiClient.get<ApiResponse<PaginatedResult<ManualEntryItem>>>(
|
|
'/admin/manual-entries',
|
|
{
|
|
params: { page, page_size: pageSize, ...query },
|
|
}
|
|
)
|
|
return data.data
|
|
}
|
|
|
|
export async function createManualEntry(payload: CreateManualEntryRequest) {
|
|
const { data } = await apiClient.post<ApiResponse<{ entry: ManualEntryItem }>>(
|
|
'/admin/manual-entries',
|
|
payload
|
|
)
|
|
return data.data
|
|
}
|
|
|
|
export async function updateManualEntry(id: number, payload: UpdateManualEntryRequest) {
|
|
const { data } = await apiClient.put<ApiResponse<ManualEntryItem>>(
|
|
`/admin/manual-entries/${id}`,
|
|
payload
|
|
)
|
|
return data.data
|
|
}
|
|
|
|
export async function deleteManualEntry(id: number) {
|
|
const { data } = await apiClient.delete<ApiResponse<{ deleted: boolean }>>(
|
|
`/admin/manual-entries/${id}`
|
|
)
|
|
return data.data
|
|
}
|
|
|
|
export async function fetchManualEntryTodayStats() {
|
|
const { data } = await apiClient.get<ApiResponse<ManualEntryAgentStats[]>>(
|
|
'/admin/manual-entries/today-stats'
|
|
)
|
|
return data.data
|
|
}
|