feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma binaryTargets for openssl 3.0 - nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal cron, http->https redirect - prisma: add origin_goods.delisted migration, sync missing schema (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz - api: CORS wildcard reflection, helmet CORP cross-origin, price backfill in persistProductDetail, categoryIcon ancestor fallback, mediaByColor per-color gallery in public goods detail - admin: /admin base path (vite + router) - import-data.mjs: udt_name casting, serial sequence advance fix
This commit is contained in:
+18
-18
@@ -1,19 +1,19 @@
|
||||
import request from './request'
|
||||
import type { LoginRequest, LoginResponse, User } from '@/types'
|
||||
|
||||
export const authApi = {
|
||||
// Login
|
||||
login: (data: LoginRequest) => {
|
||||
return request.post<any, LoginResponse>('/auth/login', data)
|
||||
},
|
||||
|
||||
// Get current user
|
||||
getCurrentUser: () => {
|
||||
return request.get<any, User>('/auth/me')
|
||||
},
|
||||
|
||||
// Logout
|
||||
logout: () => {
|
||||
return request.post('/auth/logout')
|
||||
},
|
||||
import request from './request'
|
||||
import type { LoginRequest, LoginResponse, User } from '@/types'
|
||||
|
||||
export const authApi = {
|
||||
// Login
|
||||
login: (data: LoginRequest) => {
|
||||
return request.post<any, LoginResponse>('/auth/login', data)
|
||||
},
|
||||
|
||||
// Get current user
|
||||
getCurrentUser: () => {
|
||||
return request.get<any, User>('/auth/me')
|
||||
},
|
||||
|
||||
// Logout
|
||||
logout: () => {
|
||||
return request.post('/auth/logout')
|
||||
},
|
||||
}
|
||||
@@ -1,41 +1,41 @@
|
||||
import request from './request'
|
||||
import type {
|
||||
Category,
|
||||
CategoryTree,
|
||||
CreateCategoryRequest,
|
||||
UpdateCategoryRequest,
|
||||
CategoryFilter,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const categoriesApi = {
|
||||
// Get categories list
|
||||
getCategoriesList: (params: CategoryFilter) => {
|
||||
return request.get<any, PaginatedResult<Category>>('/categories', { params })
|
||||
},
|
||||
|
||||
// Get category tree
|
||||
getCategoryTree: () => {
|
||||
return request.get<any, CategoryTree[]>('/categories')
|
||||
},
|
||||
|
||||
// Get category by id
|
||||
getCategoryById: (id: string) => {
|
||||
return request.get<any, Category>(`/categories/${id}`)
|
||||
},
|
||||
|
||||
// Create category
|
||||
createCategory: (data: CreateCategoryRequest) => {
|
||||
return request.post<any, Category>('/categories', data)
|
||||
},
|
||||
|
||||
// Update category
|
||||
updateCategory: (id: string, data: UpdateCategoryRequest) => {
|
||||
return request.patch<any, Category>(`/categories/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete category
|
||||
deleteCategory: (id: string) => {
|
||||
return request.delete(`/categories/${id}`)
|
||||
},
|
||||
import request from './request'
|
||||
import type {
|
||||
Category,
|
||||
CategoryTree,
|
||||
CreateCategoryRequest,
|
||||
UpdateCategoryRequest,
|
||||
CategoryFilter,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const categoriesApi = {
|
||||
// Get categories list
|
||||
getCategoriesList: (params: CategoryFilter) => {
|
||||
return request.get<any, PaginatedResult<Category>>('/categories', { params })
|
||||
},
|
||||
|
||||
// Get category tree
|
||||
getCategoryTree: () => {
|
||||
return request.get<any, CategoryTree[]>('/categories')
|
||||
},
|
||||
|
||||
// Get category by id
|
||||
getCategoryById: (id: string) => {
|
||||
return request.get<any, Category>(`/categories/${id}`)
|
||||
},
|
||||
|
||||
// Create category
|
||||
createCategory: (data: CreateCategoryRequest) => {
|
||||
return request.post<any, Category>('/categories', data)
|
||||
},
|
||||
|
||||
// Update category
|
||||
updateCategory: (id: string, data: UpdateCategoryRequest) => {
|
||||
return request.patch<any, Category>(`/categories/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete category
|
||||
deleteCategory: (id: string) => {
|
||||
return request.delete(`/categories/${id}`)
|
||||
},
|
||||
}
|
||||
@@ -1,35 +1,35 @@
|
||||
import request from './request'
|
||||
import type {
|
||||
Country,
|
||||
CreateCountryRequest,
|
||||
UpdateCountryRequest,
|
||||
CountryFilter,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const countriesApi = {
|
||||
// Get countries list
|
||||
getCountriesList: (params: CountryFilter) => {
|
||||
return request.get<any, PaginatedResult<Country>>('/countries', { params })
|
||||
},
|
||||
|
||||
// Get country by id
|
||||
getCountryById: (id: string) => {
|
||||
return request.get<any, Country>(`/countries/${id}`)
|
||||
},
|
||||
|
||||
// Create country
|
||||
createCountry: (data: CreateCountryRequest) => {
|
||||
return request.post<any, Country>('/countries', data)
|
||||
},
|
||||
|
||||
// Update country
|
||||
updateCountry: (id: string, data: UpdateCountryRequest) => {
|
||||
return request.patch<any, Country>(`/countries/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete country
|
||||
deleteCountry: (id: string) => {
|
||||
return request.delete(`/countries/${id}`)
|
||||
},
|
||||
import request from './request'
|
||||
import type {
|
||||
Country,
|
||||
CreateCountryRequest,
|
||||
UpdateCountryRequest,
|
||||
CountryFilter,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const countriesApi = {
|
||||
// Get countries list
|
||||
getCountriesList: (params: CountryFilter) => {
|
||||
return request.get<any, PaginatedResult<Country>>('/countries', { params })
|
||||
},
|
||||
|
||||
// Get country by id
|
||||
getCountryById: (id: string) => {
|
||||
return request.get<any, Country>(`/countries/${id}`)
|
||||
},
|
||||
|
||||
// Create country
|
||||
createCountry: (data: CreateCountryRequest) => {
|
||||
return request.post<any, Country>('/countries', data)
|
||||
},
|
||||
|
||||
// Update country
|
||||
updateCountry: (id: string, data: UpdateCountryRequest) => {
|
||||
return request.patch<any, Country>(`/countries/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete country
|
||||
deleteCountry: (id: string) => {
|
||||
return request.delete(`/countries/${id}`)
|
||||
},
|
||||
}
|
||||
+39
-39
@@ -1,29 +1,29 @@
|
||||
import request from './request'
|
||||
import type {
|
||||
import request from './request'
|
||||
import type {
|
||||
Good,
|
||||
GoodDetail,
|
||||
CreateGoodRequest,
|
||||
UpdateGoodRequest,
|
||||
BatchCreateGoodsRequest,
|
||||
BatchPriorityRequest,
|
||||
CreateGoodRequest,
|
||||
UpdateGoodRequest,
|
||||
BatchCreateGoodsRequest,
|
||||
BatchPriorityRequest,
|
||||
GoodsFilter,
|
||||
PaginatedResult,
|
||||
CreateCustomGoodRequest,
|
||||
UpdateCustomGoodContentRequest,
|
||||
} from '@/types'
|
||||
|
||||
export const goodsApi = {
|
||||
// Get goods list
|
||||
getGoodsList: (params: GoodsFilter) => {
|
||||
return request.get<any, PaginatedResult<Good>>('/goods', { params })
|
||||
},
|
||||
|
||||
// Get good by id
|
||||
getGoodById: (id: string) => {
|
||||
} from '@/types'
|
||||
|
||||
export const goodsApi = {
|
||||
// Get goods list
|
||||
getGoodsList: (params: GoodsFilter) => {
|
||||
return request.get<any, PaginatedResult<Good>>('/goods', { params })
|
||||
},
|
||||
|
||||
// Get good by id
|
||||
getGoodById: (id: string) => {
|
||||
return request.get<any, GoodDetail>(`/goods/${id}`)
|
||||
},
|
||||
|
||||
// Create good
|
||||
},
|
||||
|
||||
// Create good
|
||||
createGood: (data: CreateGoodRequest) => {
|
||||
return request.post<any, Good>('/goods', data)
|
||||
},
|
||||
@@ -35,24 +35,24 @@ export const goodsApi = {
|
||||
updateCustomGoodContent: (id: string, data: UpdateCustomGoodContentRequest) => {
|
||||
return request.patch<any, GoodDetail>(`/goods/${id}/custom-content`, data)
|
||||
},
|
||||
|
||||
// Update good
|
||||
updateGood: (id: string, data: UpdateGoodRequest) => {
|
||||
return request.patch<any, Good>(`/goods/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete good
|
||||
deleteGood: (id: string) => {
|
||||
return request.delete(`/goods/${id}`)
|
||||
},
|
||||
|
||||
// Batch create goods
|
||||
batchCreateGoods: (data: BatchCreateGoodsRequest) => {
|
||||
return request.post<any, Good[]>('/goods/batch', data)
|
||||
},
|
||||
|
||||
// Batch update priority
|
||||
batchUpdatePriority: (data: BatchPriorityRequest) => {
|
||||
return request.patch<any, { count: number }>('/goods/batch-priority', data)
|
||||
},
|
||||
|
||||
// Update good
|
||||
updateGood: (id: string, data: UpdateGoodRequest) => {
|
||||
return request.patch<any, Good>(`/goods/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete good
|
||||
deleteGood: (id: string) => {
|
||||
return request.delete(`/goods/${id}`)
|
||||
},
|
||||
|
||||
// Batch create goods
|
||||
batchCreateGoods: (data: BatchCreateGoodsRequest) => {
|
||||
return request.post<any, Good[]>('/goods/batch', data)
|
||||
},
|
||||
|
||||
// Batch update priority
|
||||
batchUpdatePriority: (data: BatchPriorityRequest) => {
|
||||
return request.patch<any, { count: number }>('/goods/batch-priority', data)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import request from './request'
|
||||
import type { OriginGood, OriginGoodsTreeResponse, PaginatedResult } from '@/types'
|
||||
|
||||
export const originGoodsApi = {
|
||||
getTree: () => {
|
||||
return request.get<any, OriginGoodsTreeResponse>('/origin-goods/tree')
|
||||
},
|
||||
|
||||
getOriginGoodsList: (params: { page?: number; pageSize?: number; keyword?: string }) => {
|
||||
return request.get<any, PaginatedResult<OriginGood>>('/origin-goods', { params })
|
||||
},
|
||||
}
|
||||
import request from './request'
|
||||
import type { OriginGood, OriginGoodsTreeResponse, PaginatedResult } from '@/types'
|
||||
|
||||
export const originGoodsApi = {
|
||||
getTree: () => {
|
||||
return request.get<any, OriginGoodsTreeResponse>('/origin-goods/tree')
|
||||
},
|
||||
|
||||
getOriginGoodsList: (params: { page?: number; pageSize?: number; keyword?: string }) => {
|
||||
return request.get<any, PaginatedResult<OriginGood>>('/origin-goods', { params })
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import request from './request'
|
||||
import type {
|
||||
Position,
|
||||
CreatePositionRequest,
|
||||
UpdatePositionRequest,
|
||||
PositionFilter,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const positionsApi = {
|
||||
// Get positions list
|
||||
getPositionsList: (params: PositionFilter) => {
|
||||
return request.get<any, PaginatedResult<Position>>('/positions', { params })
|
||||
},
|
||||
|
||||
// Get position by id
|
||||
getPositionById: (id: string) => {
|
||||
return request.get<any, Position>(`/positions/${id}`)
|
||||
},
|
||||
|
||||
// Create position
|
||||
createPosition: (data: CreatePositionRequest) => {
|
||||
return request.post<any, Position>('/positions', data)
|
||||
},
|
||||
|
||||
// Update position
|
||||
updatePosition: (id: string, data: UpdatePositionRequest) => {
|
||||
return request.patch<any, Position>(`/positions/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete position
|
||||
deletePosition: (id: string) => {
|
||||
return request.delete(`/positions/${id}`)
|
||||
},
|
||||
import request from './request'
|
||||
import type {
|
||||
Position,
|
||||
CreatePositionRequest,
|
||||
UpdatePositionRequest,
|
||||
PositionFilter,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const positionsApi = {
|
||||
// Get positions list
|
||||
getPositionsList: (params: PositionFilter) => {
|
||||
return request.get<any, PaginatedResult<Position>>('/positions', { params })
|
||||
},
|
||||
|
||||
// Get position by id
|
||||
getPositionById: (id: string) => {
|
||||
return request.get<any, Position>(`/positions/${id}`)
|
||||
},
|
||||
|
||||
// Create position
|
||||
createPosition: (data: CreatePositionRequest) => {
|
||||
return request.post<any, Position>('/positions', data)
|
||||
},
|
||||
|
||||
// Update position
|
||||
updatePosition: (id: string, data: UpdatePositionRequest) => {
|
||||
return request.patch<any, Position>(`/positions/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete position
|
||||
deletePosition: (id: string) => {
|
||||
return request.delete(`/positions/${id}`)
|
||||
},
|
||||
}
|
||||
@@ -1,81 +1,81 @@
|
||||
import axios from 'axios'
|
||||
import type { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import router from '@/router'
|
||||
|
||||
const request: AxiosInstance = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE || '/api',
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
// Session tokens live in HttpOnly cookies — send them along.
|
||||
withCredentials: true,
|
||||
})
|
||||
|
||||
// Response interceptor
|
||||
request.interceptors.response.use(
|
||||
(response: AxiosResponse) => {
|
||||
// Backend wraps everything in { data, success } — unwrap to data
|
||||
const body = response.data
|
||||
if (body && typeof body === 'object' && 'success' in body && 'data' in body) {
|
||||
return body.data
|
||||
}
|
||||
return body
|
||||
},
|
||||
async (error: AxiosError) => {
|
||||
// Access token expired: try the refresh cookie once, then retry the
|
||||
// original request. A second 401 (refresh failed) logs the user out.
|
||||
const config = error.config as (InternalAxiosRequestConfig & { _retried?: boolean }) | undefined
|
||||
if (
|
||||
error.response?.status === 401 &&
|
||||
config &&
|
||||
!config._retried &&
|
||||
!config.url?.includes('/auth/login') &&
|
||||
!config.url?.includes('/auth/refresh')
|
||||
) {
|
||||
config._retried = true
|
||||
try {
|
||||
await axios.post(
|
||||
`${import.meta.env.VITE_API_BASE || '/api'}/auth/refresh`,
|
||||
{},
|
||||
{ withCredentials: true },
|
||||
)
|
||||
return request.request(config)
|
||||
} catch {
|
||||
// fall through to the 401 handling below
|
||||
}
|
||||
}
|
||||
|
||||
if (error.response) {
|
||||
const { status, data } = error.response
|
||||
|
||||
switch (status) {
|
||||
case 401:
|
||||
ElMessage.error('Unauthorized, please login')
|
||||
router.push('/login')
|
||||
break
|
||||
case 403:
|
||||
ElMessage.error('Forbidden')
|
||||
break
|
||||
case 404:
|
||||
ElMessage.error('Resource not found')
|
||||
break
|
||||
case 500:
|
||||
ElMessage.error('Server error')
|
||||
break
|
||||
default:
|
||||
const errorMessage = (data as any)?.message || 'Request failed'
|
||||
ElMessage.error(errorMessage)
|
||||
}
|
||||
} else if (error.request) {
|
||||
ElMessage.error('Network error')
|
||||
} else {
|
||||
ElMessage.error('Request failed')
|
||||
}
|
||||
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default request
|
||||
import axios from 'axios'
|
||||
import type { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import router from '@/router'
|
||||
|
||||
const request: AxiosInstance = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE || '/api',
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
// Session tokens live in HttpOnly cookies — send them along.
|
||||
withCredentials: true,
|
||||
})
|
||||
|
||||
// Response interceptor
|
||||
request.interceptors.response.use(
|
||||
(response: AxiosResponse) => {
|
||||
// Backend wraps everything in { data, success } — unwrap to data
|
||||
const body = response.data
|
||||
if (body && typeof body === 'object' && 'success' in body && 'data' in body) {
|
||||
return body.data
|
||||
}
|
||||
return body
|
||||
},
|
||||
async (error: AxiosError) => {
|
||||
// Access token expired: try the refresh cookie once, then retry the
|
||||
// original request. A second 401 (refresh failed) logs the user out.
|
||||
const config = error.config as (InternalAxiosRequestConfig & { _retried?: boolean }) | undefined
|
||||
if (
|
||||
error.response?.status === 401 &&
|
||||
config &&
|
||||
!config._retried &&
|
||||
!config.url?.includes('/auth/login') &&
|
||||
!config.url?.includes('/auth/refresh')
|
||||
) {
|
||||
config._retried = true
|
||||
try {
|
||||
await axios.post(
|
||||
`${import.meta.env.VITE_API_BASE || '/api'}/auth/refresh`,
|
||||
{},
|
||||
{ withCredentials: true },
|
||||
)
|
||||
return request.request(config)
|
||||
} catch {
|
||||
// fall through to the 401 handling below
|
||||
}
|
||||
}
|
||||
|
||||
if (error.response) {
|
||||
const { status, data } = error.response
|
||||
|
||||
switch (status) {
|
||||
case 401:
|
||||
ElMessage.error('Unauthorized, please login')
|
||||
router.push('/login')
|
||||
break
|
||||
case 403:
|
||||
ElMessage.error('Forbidden')
|
||||
break
|
||||
case 404:
|
||||
ElMessage.error('Resource not found')
|
||||
break
|
||||
case 500:
|
||||
ElMessage.error('Server error')
|
||||
break
|
||||
default:
|
||||
const errorMessage = (data as any)?.message || 'Request failed'
|
||||
ElMessage.error(errorMessage)
|
||||
}
|
||||
} else if (error.request) {
|
||||
ElMessage.error('Network error')
|
||||
} else {
|
||||
ElMessage.error('Request failed')
|
||||
}
|
||||
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default request
|
||||
|
||||
+16
-16
@@ -1,13 +1,13 @@
|
||||
import request from './request'
|
||||
import type { SyncLog } from '@/types'
|
||||
|
||||
export const syncApi = {
|
||||
syncProducts: () => {
|
||||
return request.post<any, { message: string }>('/sync/products')
|
||||
},
|
||||
|
||||
import request from './request'
|
||||
import type { SyncLog } from '@/types'
|
||||
|
||||
export const syncApi = {
|
||||
syncProducts: () => {
|
||||
return request.post<any, { message: string }>('/sync/products')
|
||||
},
|
||||
|
||||
syncCategories: () => {
|
||||
return request.post<any, { message: string }>('/sync/categories')
|
||||
return request.post<any, { message: string }>('/sync/categories')
|
||||
},
|
||||
|
||||
syncProductDetails: () => {
|
||||
@@ -19,10 +19,10 @@ export const syncApi = {
|
||||
`/sync/products/${goodId}/detail`,
|
||||
)
|
||||
},
|
||||
|
||||
getSyncStatus: (limit?: number) => {
|
||||
return request.get<any, SyncLog[]>('/sync/status', {
|
||||
params: limit ? { limit } : undefined,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
getSyncStatus: (limit?: number) => {
|
||||
return request.get<any, SyncLog[]>('/sync/status', {
|
||||
params: limit ? { limit } : undefined,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import request from './request'
|
||||
import type {
|
||||
TagGroup,
|
||||
CreateTagGroupRequest,
|
||||
UpdateTagGroupRequest,
|
||||
ReorderTagGroupsRequest,
|
||||
} from '@/types'
|
||||
|
||||
export const tagGroupsApi = {
|
||||
getTagGroupsList: () => {
|
||||
return request.get<any, TagGroup[]>('/tag-groups')
|
||||
},
|
||||
|
||||
getTagGroupById: (id: string) => {
|
||||
return request.get<any, TagGroup>(`/tag-groups/${id}`)
|
||||
},
|
||||
|
||||
createTagGroup: (data: CreateTagGroupRequest) => {
|
||||
return request.post<any, TagGroup>('/tag-groups', data)
|
||||
},
|
||||
|
||||
updateTagGroup: (id: string, data: UpdateTagGroupRequest) => {
|
||||
return request.patch<any, TagGroup>(`/tag-groups/${id}`, data)
|
||||
},
|
||||
|
||||
deleteTagGroup: (id: string) => {
|
||||
return request.delete(`/tag-groups/${id}`)
|
||||
},
|
||||
|
||||
reorderTagGroups: (data: ReorderTagGroupsRequest) => {
|
||||
return request.patch('/tag-groups/sort', data)
|
||||
},
|
||||
}
|
||||
import request from './request'
|
||||
import type {
|
||||
TagGroup,
|
||||
CreateTagGroupRequest,
|
||||
UpdateTagGroupRequest,
|
||||
ReorderTagGroupsRequest,
|
||||
} from '@/types'
|
||||
|
||||
export const tagGroupsApi = {
|
||||
getTagGroupsList: () => {
|
||||
return request.get<any, TagGroup[]>('/tag-groups')
|
||||
},
|
||||
|
||||
getTagGroupById: (id: string) => {
|
||||
return request.get<any, TagGroup>(`/tag-groups/${id}`)
|
||||
},
|
||||
|
||||
createTagGroup: (data: CreateTagGroupRequest) => {
|
||||
return request.post<any, TagGroup>('/tag-groups', data)
|
||||
},
|
||||
|
||||
updateTagGroup: (id: string, data: UpdateTagGroupRequest) => {
|
||||
return request.patch<any, TagGroup>(`/tag-groups/${id}`, data)
|
||||
},
|
||||
|
||||
deleteTagGroup: (id: string) => {
|
||||
return request.delete(`/tag-groups/${id}`)
|
||||
},
|
||||
|
||||
reorderTagGroups: (data: ReorderTagGroupsRequest) => {
|
||||
return request.patch('/tag-groups/sort', data)
|
||||
},
|
||||
}
|
||||
|
||||
+40
-40
@@ -1,41 +1,41 @@
|
||||
import request from './request'
|
||||
import type {
|
||||
Tag,
|
||||
CreateTagRequest,
|
||||
UpdateTagRequest,
|
||||
TagFilter,
|
||||
ReorderTagsRequest,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const tagsApi = {
|
||||
// Get tags list
|
||||
getTagsList: (params: TagFilter) => {
|
||||
return request.get<any, PaginatedResult<Tag>>('/tags', { params })
|
||||
},
|
||||
|
||||
// Get tag by id
|
||||
getTagById: (id: string) => {
|
||||
return request.get<any, Tag>(`/tags/${id}`)
|
||||
},
|
||||
|
||||
// Create tag
|
||||
createTag: (data: CreateTagRequest) => {
|
||||
return request.post<any, Tag>('/tags', data)
|
||||
},
|
||||
|
||||
// Update tag
|
||||
updateTag: (id: string, data: UpdateTagRequest) => {
|
||||
return request.patch<any, Tag>(`/tags/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete tag
|
||||
deleteTag: (id: string) => {
|
||||
return request.delete(`/tags/${id}`)
|
||||
},
|
||||
|
||||
// Reorder tags (and/or move across groups)
|
||||
reorderTags: (data: ReorderTagsRequest) => {
|
||||
return request.patch('/tags/sort', data)
|
||||
},
|
||||
import request from './request'
|
||||
import type {
|
||||
Tag,
|
||||
CreateTagRequest,
|
||||
UpdateTagRequest,
|
||||
TagFilter,
|
||||
ReorderTagsRequest,
|
||||
PaginatedResult,
|
||||
} from '@/types'
|
||||
|
||||
export const tagsApi = {
|
||||
// Get tags list
|
||||
getTagsList: (params: TagFilter) => {
|
||||
return request.get<any, PaginatedResult<Tag>>('/tags', { params })
|
||||
},
|
||||
|
||||
// Get tag by id
|
||||
getTagById: (id: string) => {
|
||||
return request.get<any, Tag>(`/tags/${id}`)
|
||||
},
|
||||
|
||||
// Create tag
|
||||
createTag: (data: CreateTagRequest) => {
|
||||
return request.post<any, Tag>('/tags', data)
|
||||
},
|
||||
|
||||
// Update tag
|
||||
updateTag: (id: string, data: UpdateTagRequest) => {
|
||||
return request.patch<any, Tag>(`/tags/${id}`, data)
|
||||
},
|
||||
|
||||
// Delete tag
|
||||
deleteTag: (id: string) => {
|
||||
return request.delete(`/tags/${id}`)
|
||||
},
|
||||
|
||||
// Reorder tags (and/or move across groups)
|
||||
reorderTags: (data: ReorderTagsRequest) => {
|
||||
return request.patch('/tags/sort', data)
|
||||
},
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import request from './request'
|
||||
|
||||
export interface UploadResult {
|
||||
url: string
|
||||
filename: string
|
||||
}
|
||||
|
||||
export const uploadApi = {
|
||||
uploadImage: (file: File) => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request.post<any, UploadResult>('/upload/image', formData)
|
||||
},
|
||||
}
|
||||
import request from './request'
|
||||
|
||||
export interface UploadResult {
|
||||
url: string
|
||||
filename: string
|
||||
}
|
||||
|
||||
export const uploadApi = {
|
||||
uploadImage: (file: File) => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request.post<any, UploadResult>('/upload/image', formData)
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user