task-84(店铺中心): 实现新增店铺密钥表单
新增 shop-key-form-model.ts(备注/紫鸟账号/令牌校验与 camel 请求体序列化, 镜像 Java NotBlank/Size 规则,令牌去 Bearer 前缀) 并在 shop-key-api.ts 增加 submitCreateShopKey(POST /api/admin/shop-keys)。 TDD: task-84.test.ts 8 用例先 RED 后 GREEN。
This commit is contained in:
@@ -1,7 +1,19 @@
|
||||
/** 店铺密钥列表加载适配(任务 82):GET /api/admin/shop-keys + 分页归一与解析。 */
|
||||
/** 店铺密钥列表加载与新增适配(任务 82/84):GET/POST /api/admin/shop-keys + 归一与解析。 */
|
||||
import { http } from '@/api/http'
|
||||
import { parseShopKeyPage } from './shop-key-model'
|
||||
import { normalizeKeyListParams, toKeyPageQuery, type ShopKeyListParams, type ShopKeyPageResult } from './shop-dto.ts'
|
||||
import { unwrap } from '@/api/envelope'
|
||||
import { parseShopKeyPage, toShopKeyItem } from './shop-key-model.ts'
|
||||
import {
|
||||
normalizeKeyListParams,
|
||||
toKeyPageQuery,
|
||||
type ShopKeyItem,
|
||||
type ShopKeyListParams,
|
||||
type ShopKeyPageResult,
|
||||
} from './shop-dto.ts'
|
||||
import {
|
||||
toShopKeyCreateRequest,
|
||||
validateShopKeyForm,
|
||||
type ShopKeyFormValues,
|
||||
} from './shop-key-form-model.ts'
|
||||
|
||||
export const SHOP_KEYS_ENDPOINT = '/api/admin/shop-keys'
|
||||
|
||||
@@ -10,3 +22,17 @@ export async function fetchShopKeyList(params: Partial<ShopKeyListParams> = {}):
|
||||
const { data } = await http.get<unknown>(SHOP_KEYS_ENDPOINT, { params: toKeyPageQuery(normalized) })
|
||||
return parseShopKeyPage(data)
|
||||
}
|
||||
|
||||
/** 提交新增店铺密钥:先校验(失败抛首条错误不发请求),再 POST,解析返回的新记录。 */
|
||||
export async function submitCreateShopKey(form: ShopKeyFormValues): Promise<ShopKeyItem> {
|
||||
const { valid, errors } = validateShopKeyForm(form)
|
||||
if (!valid) {
|
||||
throw new Error(Object.values(errors)[0] || '店铺密钥表单校验未通过')
|
||||
}
|
||||
const { data } = await http.post<unknown>(SHOP_KEYS_ENDPOINT, toShopKeyCreateRequest(form))
|
||||
const item = toShopKeyItem(unwrap<unknown>(data))
|
||||
if (!item) {
|
||||
throw new Error('新增店铺密钥响应异常:未返回有效记录')
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/** 店铺密钥表单模型(任务 84/85 共用):新增/编辑都镜像 Java ShopKeyCreateRequest/UpdateRequest 的
|
||||
* 字段、长度校验与敏感字段语义;纯逻辑,无框架依赖。 */
|
||||
|
||||
export const SHOP_KEY_REMARK_MAX_LEN = 128
|
||||
export const SHOP_KEY_ACCOUNT_MAX_LEN = 128
|
||||
export const SHOP_KEY_TOKEN_MAX_LEN = 512
|
||||
|
||||
export interface ShopKeyFormValues {
|
||||
remarkName: string
|
||||
ziniaoAccountName: string
|
||||
/** 紫鸟令牌:敏感输入,提交前需去除 "Bearer " 前缀与首尾空白。 */
|
||||
ziniaoToken: string
|
||||
}
|
||||
|
||||
export interface ShopKeyFormErrors {
|
||||
remarkName?: string
|
||||
ziniaoAccountName?: string
|
||||
ziniaoToken?: string
|
||||
}
|
||||
|
||||
/** 发送 POST/PUT /api/admin/shop-keys 的请求体(与 Java 请求 DTO camelCase 对齐)。 */
|
||||
export interface ShopKeyPayload {
|
||||
remarkName?: string
|
||||
ziniaoAccountName: string
|
||||
ziniaoToken: string
|
||||
}
|
||||
|
||||
export function emptyShopKeyForm(): ShopKeyFormValues {
|
||||
return { remarkName: '', ziniaoAccountName: '', ziniaoToken: '' }
|
||||
}
|
||||
|
||||
/** 归一紫鸟令牌:去首尾空白并去除大小写不敏感的 "Bearer " 前缀(镜像后端 normalizeToken)。 */
|
||||
export function normalizeZiniaoToken(value: string): string {
|
||||
let token = (value || '').trim()
|
||||
if (token.toUpperCase().startsWith('BEARER ')) {
|
||||
token = token.slice(7).trim()
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
function remarkTrimmed(value: string): string {
|
||||
return (value || '').trim()
|
||||
}
|
||||
|
||||
/** 校验新增/编辑表单(镜像后端 NotBlank/Size 规则),返回逐字段错误。 */
|
||||
export function validateShopKeyForm(form: ShopKeyFormValues): { valid: boolean; errors: ShopKeyFormErrors } {
|
||||
const errors: ShopKeyFormErrors = {}
|
||||
const remark = remarkTrimmed(form.remarkName)
|
||||
if (remark.length > SHOP_KEY_REMARK_MAX_LEN) {
|
||||
errors.remarkName = `备注名长度不能超过${SHOP_KEY_REMARK_MAX_LEN}个字符`
|
||||
}
|
||||
const account = (form.ziniaoAccountName || '').trim()
|
||||
if (!account) {
|
||||
errors.ziniaoAccountName = '紫鸟账号名称不能为空'
|
||||
} else if (account.length > SHOP_KEY_ACCOUNT_MAX_LEN) {
|
||||
errors.ziniaoAccountName = `紫鸟账号名称长度不能超过${SHOP_KEY_ACCOUNT_MAX_LEN}个字符`
|
||||
}
|
||||
const token = normalizeZiniaoToken(form.ziniaoToken)
|
||||
if (!token) {
|
||||
errors.ziniaoToken = '紫鸟令牌不能为空'
|
||||
} else if (token.length > SHOP_KEY_TOKEN_MAX_LEN) {
|
||||
errors.ziniaoToken = `紫鸟令牌长度不能超过${SHOP_KEY_TOKEN_MAX_LEN}个字符`
|
||||
}
|
||||
return { valid: Object.keys(errors).length === 0, errors }
|
||||
}
|
||||
|
||||
/** 新增表单 → 创建请求体:账号/令牌归一,备注为空则不下发。 */
|
||||
export function toShopKeyCreateRequest(form: ShopKeyFormValues): ShopKeyPayload {
|
||||
const remark = remarkTrimmed(form.remarkName)
|
||||
const payload: ShopKeyPayload = {
|
||||
ziniaoAccountName: (form.ziniaoAccountName || '').trim(),
|
||||
ziniaoToken: normalizeZiniaoToken(form.ziniaoToken),
|
||||
}
|
||||
if (remark) payload.remarkName = remark
|
||||
return payload
|
||||
}
|
||||
Reference in New Issue
Block a user