This commit is contained in:
zlwu committed 2026-07-17 21:59:47 +08:00
1 parent 8be55c08e9
commit a903fcf6d4
75 files changed
+9547 -124

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
/**
* 管理端公共选项(审批人选人等)
* 协议:门户信封 code===200
*/
import { request, parseResponseJson } from '@/utils/request'
function unwrap(res) {
const body = parseResponseJson(res)
if (!body || typeof body !== 'object') {
throw new Error('接口响应异常')
}
if (body.code != null && body.code !== 200) {
throw new Error(body.message || body.msg || '请求失败')
}
return body.data != null ? body.data : body
}
/**
* @returns {Promise<Array<{ userId: string, nickName: string, userNo: string, label: string }>>}
*/
export async function fetchUserOptions() {
const res = await request({
url: '/web/admin/users/options',
method: 'GET'
})
const data = unwrap(res)
const list = Array.isArray(data) ? data : []
return list
.map((item) => {
const userId = String(item.value ?? item.userId ?? item.id ?? '')
const nickName = String(item.nickName ?? item.label ?? item.userName ?? '')
const userNo = String(item.userNo ?? item.userName ?? '')
return {
userId,
nickName,
userNo,
label: nickName || userNo || userId
}
})
.filter((u) => u.userId)
}
+191
View File
@@ -0,0 +1,191 @@
/**
* 报销模块 API(REST,协议 code===0 / msg / data.rows)
* 路径挂在 /api 下:/reimburses、/advances、/expense-items、/attachments
*/
import { request, parseResponseJson } from '@/utils/request'
function unwrap(res) {
const body = parseResponseJson(res)
if (!body || typeof body !== 'object') {
throw new Error('接口响应异常')
}
if (body.code != null && body.code !== 0) {
throw new Error(body.msg || body.message || '请求失败')
}
return body.data != null ? body.data : body
}
async function get(url, params = {}) {
const res = await request({ url, method: 'GET', data: params, params })
return unwrap(res)
}
async function post(url, data = {}) {
const res = await request({ url, method: 'POST', data })
return unwrap(res)
}
async function put(url, data = {}, params = {}) {
const res = await request({ url, method: 'PUT', data, params })
return unwrap(res)
}
function pageParams(query = {}) {
const { pageNum, page, pageSize, ...rest } = query
const params = {
page: pageNum ?? page ?? 1,
pageSize: pageSize ?? 20
}
Object.keys(rest).forEach((k) => {
if (rest[k] != null && rest[k] !== '') params[k] = rest[k]
})
return params
}
function normalizeList(data) {
if (Array.isArray(data)) return { rows: data, total: data.length }
const d = data || {}
return {
rows: d.rows || d.list || [],
total: d.total ?? 0
}
}
// ── 费用项目 ──
export async function getExpenseItemTree() {
const data = await get('/expense-items/tree')
return Array.isArray(data) ? data : []
}
/** 展平可选叶子费用项目(供 picker) */
export function flattenExpenseLeaves(tree, path = []) {
const out = []
;(tree || []).forEach((node) => {
const name = node.itemName || node.item_name || ''
const nextPath = path.concat(name)
const children = node.children || []
if (children.length) {
out.push(...flattenExpenseLeaves(children, nextPath))
} else {
out.push({
id: String(node.id),
name,
pathLabel: nextPath.join(' / ')
})
}
})
return out
}
// ── 报销 ──
export async function listMyReimburse(query = {}) {
return normalizeList(await get('/reimburses/my', pageParams(query)))
}
export async function listPendingReimburse(query = {}) {
return normalizeList(await get('/reimburses/pending-approval', pageParams(query)))
}
export async function listApprovedByMeReimburse(query = {}) {
return normalizeList(await get('/reimburses/approved-by-me', pageParams(query)))
}
export async function getReimburse(id) {
return get(`/reimburses/${String(id)}`)
}
export async function generateReimburseTitle(reimburseDate) {
const params = {}
if (reimburseDate) params.reimburseDate = reimburseDate
return get('/reimburses/generate-title', params)
}
export function createReimburse(data) {
return post('/reimburses/', data)
}
export function updateReimburse(id, data) {
return put(`/reimburses/${String(id)}`, data)
}
export function submitReimburse(id) {
return post(`/reimburses/${String(id)}/submit`)
}
export function approveReimburse(id, approvalOpinion = '') {
return post(`/reimburses/${String(id)}/approve`, { approvalOpinion })
}
export function rejectReimburse(id, approvalOpinion = '') {
return post(`/reimburses/${String(id)}/reject`, { approvalOpinion })
}
export async function getReimburseApprovalHistory(id) {
const data = await get(`/reimburses/${String(id)}/approval-history`)
return Array.isArray(data) ? data : []
}
// ── 借款(备用金) ──
export async function listMyAdvance(query = {}) {
return normalizeList(await get('/advances/my', pageParams(query)))
}
export async function listPendingAdvance(query = {}) {
return normalizeList(await get('/advances/pending-approval', pageParams(query)))
}
export async function listApprovedByMeAdvance(query = {}) {
return normalizeList(await get('/advances/approved-by-me', pageParams(query)))
}
export async function getAdvance(id) {
return get(`/advances/${String(id)}`)
}
export function createAdvance(data) {
return post('/advances/', data)
}
export function submitAdvance(id) {
return post(`/advances/${String(id)}/submit`)
}
export function approveAdvance(id, approvalOpinion = '') {
return post(`/advances/${String(id)}/approve`, { approvalOpinion })
}
export function rejectAdvance(id, approvalOpinion = '') {
return post(`/advances/${String(id)}/reject`, { approvalOpinion })
}
export async function getAdvanceApprovalHistory(id) {
const data = await get(`/advances/${String(id)}/approval-history`)
return Array.isArray(data) ? data : []
}
// ── 附件 ──
export async function listAttachments(bizType, bizId) {
const data = await get('/attachments/list', {
biz_type: bizType,
biz_id: String(bizId)
})
return Array.isArray(data) ? data : []
}
export async function bindAttachments(ids, bizType, bizId) {
if (!ids?.length) return 0
const q = [
`ids=${encodeURIComponent(ids.map(String).join(','))}`,
`biz_type=${encodeURIComponent(bizType)}`,
`biz_id=${encodeURIComponent(String(bizId))}`
].join('&')
return put(`/attachments/bind-biz?${q}`, {})
}
export async function previewAttachment(id) {
return get(`/attachments/preview/${String(id)}`)
}
+215
View File
@@ -0,0 +1,215 @@
/**
* CRM 管理端接口(复用 /web/crm/*,需 admin JWT)
*/
import { request, parseResponseJson } from '@/utils/request'
function unwrap(res) {
const body = parseResponseJson(res)
if (!body || typeof body !== 'object') {
throw new Error('接口响应异常')
}
if (body.code != null && body.code !== 200) {
throw new Error(body.message || '请求失败')
}
return body.data != null ? body.data : body
}
async function post(url, data = {}) {
const res = await request({ url, method: 'POST', data })
return unwrap(res)
}
async function get(url, params = {}) {
const res = await request({ url, method: 'GET', data: params, params })
return unwrap(res)
}
function pageBody(query = {}) {
const { pageNum, page, pageSize, ...rest } = query
return {
page: pageNum ?? page ?? 1,
pageSize: pageSize ?? 20,
...rest
}
}
function normalizeList(data) {
if (Array.isArray(data)) {
return { rows: data, total: data.length }
}
const d = data || {}
return {
rows: d.list || d.rows || [],
total: d.total ?? (d.list || d.rows || []).length
}
}
// ── 线索 ──
export async function listClue(query = {}) {
const { pageNum, pageSize, ...rest } = query
return normalizeList(await post('/web/crm/clue/list', pageBody({ pageNum, pageSize, ...rest })))
}
export async function listMyClue(query = {}) {
const { pageNum, pageSize, ...rest } = query
return normalizeList(await post('/web/crm/clue/mine', pageBody({ pageNum, pageSize, ...rest })))
}
export async function getClue(id) {
return post('/web/crm/clue/detail', { id: String(id) })
}
export function addClue(data) {
return post('/web/crm/clue/add', data)
}
export function updateClue(data) {
return post('/web/crm/clue/update', data)
}
export function convertClue(data) {
return post('/web/crm/clue/convert', {
id: String(data.clueId ?? data.id),
customerName: data.customerName,
customerType: data.customerType,
contactName: data.contactName,
contactMobile: data.contactMobile,
remark: data.remark
})
}
export function markClueInvalid(data) {
return post('/web/crm/clue/invalid', {
id: data.id != null ? String(data.id) : undefined,
remark: data.remark
})
}
export async function listClueFollow(clueId, pageNum = 1, pageSize = 20) {
return normalizeList(
await post('/web/crm/clue/follow/list', {
clueId: String(clueId),
page: pageNum,
pageSize
})
)
}
export function addClueFollow(data) {
return post('/web/crm/clue/follow/add', {
...data,
clueId: String(data.clueId)
})
}
// ── 商机 ──
export async function listOpportunity(query = {}) {
const { pageNum, pageSize, ...rest } = query
return normalizeList(
await post('/web/crm/opportunity/list', pageBody({ pageNum, pageSize, ...rest }))
)
}
export async function getOpportunity(id) {
return post('/web/crm/opportunity/detail', { id: String(id) })
}
export async function listOpportunityFollow(opportunityId, pageNum = 1, pageSize = 20) {
return normalizeList(
await post('/web/crm/opportunity/follow/list', {
opportunityId: String(opportunityId),
page: pageNum,
pageSize
})
)
}
export function addOpportunityFollow(data) {
return post('/web/crm/opportunity/follow/add', {
...data,
opportunityId: String(data.opportunityId)
})
}
// ── 客户 ──
export async function listCustomer(query = {}) {
const { pageNum, pageSize, ...rest } = query
return normalizeList(
await post('/web/crm/customer/list', pageBody({ pageNum, pageSize, ...rest }))
)
}
export async function listMyCustomer(query = {}) {
const { pageNum, pageSize, ...rest } = query
return normalizeList(
await post('/web/crm/customer/mine', pageBody({ pageNum, pageSize, ...rest }))
)
}
export async function getCustomer(id) {
return post('/web/crm/customer/detail', { id: String(id) })
}
export async function listCustomerFollow(customerId, pageNum = 1, pageSize = 20) {
return normalizeList(
await post('/web/crm/customer/follow/byCustomer', {
customerId: String(customerId),
page: pageNum,
pageSize
})
)
}
export function addCustomerFollow(data) {
return post('/web/crm/customer/follow/add', {
...data,
customerId: String(data.customerId)
})
}
// ── 公海 ──
export async function listPoolCustomer(query = {}) {
const { pageNum, pageSize, ...rest } = query
return normalizeList(
await post('/web/crm/customer/pool/list', pageBody({ pageNum, pageSize, ...rest }))
)
}
export function claimCustomer(ids) {
const idList = Array.isArray(ids) ? ids.map(String) : [String(ids)]
return post('/web/crm/customer/claim', { ids: idList })
}
// ── 报价 ──
export async function listQuote(query = {}) {
const { pageNum, pageSize, ...rest } = query
return normalizeList(await post('/web/crm/quote/list', pageBody({ pageNum, pageSize, ...rest })))
}
export async function getQuote(id) {
return post('/web/crm/quote/detail', { id: String(id) })
}
// ── 合同(GET) ──
export async function listContract(query = {}) {
const params = {
pageNum: query.pageNum ?? 1,
pageSize: query.pageSize ?? 20
}
;['keyword', 'contractNo', 'contractName', 'customerName', 'status', 'approvalStatus'].forEach(
(k) => {
if (query[k] != null && query[k] !== '') params[k] = query[k]
}
)
return normalizeList(await get('/web/crm/contract/list', params))
}
export async function getContract(id) {
return get(`/web/crm/contract/${String(id)}`)
}
+126
View File
@@ -0,0 +1,126 @@
/**
* 地磅模块 API(直出 JSON,对齐原 dibang;路径 /plans /weighing /inventory /dashboard)
*/
import { request, parseResponseJson } from '@/utils/request'
function extractError(body) {
if (!body || typeof body !== 'object') return '请求失败'
const detail = body.detail
if (typeof detail === 'string') return detail
if (Array.isArray(detail)) {
return detail.map((x) => x?.msg || x?.message || '').filter(Boolean).join(';') || '请求失败'
}
return body.msg || body.message || '请求失败'
}
function unwrap(res) {
if (res.statusCode === 204) return null
if (res.statusCode >= 400) {
throw new Error(extractError(parseResponseJson(res)))
}
const body = parseResponseJson(res)
if (body == null) return body
if (Array.isArray(body)) return body
if (typeof body === 'object' && body.code != null) {
if (body.code !== 200 && body.code !== 0) {
throw new Error(body.message || body.msg || '请求失败')
}
return body.data != null ? body.data : body
}
return body
}
async function get(url, params = {}) {
const res = await request({ url, method: 'GET', data: params, params })
return unwrap(res)
}
async function post(url, data = {}) {
const res = await request({ url, method: 'POST', data })
return unwrap(res)
}
async function patch(url, data = {}) {
const res = await request({ url, method: 'PATCH', data })
return unwrap(res)
}
function asList(data) {
return Array.isArray(data) ? data : []
}
/** 集合根须带尾斜杠,避免 307 丢 Authorization */
function root(path) {
return path.endsWith('/') ? path : `${path}/`
}
// ── 仪表盘 ──
export async function getDashboardStats() {
return (await get('/dashboard/stats')) || {}
}
export async function getInboundByCargo() {
return asList(await get('/dashboard/inbound/by-cargo'))
}
export async function getOutboundByCargo() {
return asList(await get('/dashboard/outbound/by-cargo'))
}
// ── 计划 ──
export async function listPlans(params = {}) {
return asList(await get(root('/plans'), params))
}
export async function getPlan(id) {
return get(`/plans/${String(id)}`)
}
export async function getPlanRelated(id) {
return (await get(`/plans/${String(id)}/related`)) || { inventories: [], weighings: [] }
}
// ── 地磅单 ──
export async function listWeighing(params = {}) {
return asList(await get(root('/weighing'), params))
}
export async function getWeighing(id) {
return get(`/weighing/${String(id)}`)
}
export async function getWeighingRelated(id) {
return (await get(`/weighing/${String(id)}/related`)) || { plan: null, inventory: null }
}
export function updateWeighing(id, data) {
return patch(`/weighing/${String(id)}`, data)
}
export function voidWeighing(id) {
return post(`/weighing/${String(id)}/void`, {})
}
// ── 出入库 ──
export async function listInventory(params = {}) {
return asList(await get(root('/inventory'), params))
}
export async function getInventory(id) {
return get(`/inventory/${String(id)}`)
}
export async function getInventoryRelated(id) {
return (await get(`/inventory/${String(id)}/related`)) || { plan: null, weighing: null }
}
export function createInventoryLinkForPlan(purchasePlanId, remarks) {
return post('/inventory/create-link-for-plan', {
purchasePlanId: String(purchasePlanId),
remarks
})
}
+124
View File
@@ -0,0 +1,124 @@
/**
* 运输模块 API(/transport/*)
* 协议与报销侧 bx HTTP 一致:有信封时 code===0;直出 { list, total } 亦可。
*/
import { request, parseResponseJson } from '@/utils/request'
function unwrap(res) {
const body = parseResponseJson(res)
if (!body || typeof body !== 'object') {
throw new Error('接口响应异常')
}
if (body.code != null && body.code !== 0) {
throw new Error(body.msg || body.message || '请求失败')
}
return body.data != null ? body.data : body
}
async function get(url, params = {}) {
const res = await request({ url, method: 'GET', data: params, params })
return unwrap(res)
}
async function post(url, data = {}) {
const res = await request({ url, method: 'POST', data })
return unwrap(res)
}
async function patch(url, data = {}) {
const res = await request({ url, method: 'PATCH', data })
return unwrap(res)
}
function pageParams(query = {}) {
const { pageNum, page, pageSize, ...rest } = query
const params = {
page: pageNum ?? page ?? 1,
pageSize: pageSize ?? 20
}
Object.keys(rest).forEach((k) => {
if (rest[k] != null && rest[k] !== '') params[k] = rest[k]
})
return params
}
function normalizeList(data) {
if (Array.isArray(data)) return { rows: data, total: data.length }
const d = data || {}
return {
rows: d.rows || d.list || [],
total: d.total ?? 0
}
}
// ── 运输计划 ──
export async function listPlans(query = {}) {
return normalizeList(await get('/transport/plan/', pageParams(query)))
}
export async function getPlan(id) {
return get(`/transport/plan/${String(id)}`)
}
export async function getPlanArrangeInfo(id) {
return get(`/transport/plan/${String(id)}/arrange-info`)
}
export async function updateProductCerts(id, products) {
return patch(`/transport/plan/${String(id)}/product-certs`, { products })
}
export async function setHazardCertReady(id, ready) {
return patch(`/transport/plan/${String(id)}/hazard-cert-ready`, { ready: !!ready })
}
export async function archivePlan(id, body) {
return post(`/transport/plan/${String(id)}/archive`, body || {})
}
export async function arrangeTransport(planId, data) {
return post(`/transport/order/arrange/${String(planId)}`, data)
}
// ── 车辆 / 驾押(安排运输选人)──
export async function listVehicles(query = {}) {
return normalizeList(await get('/transport/vehicle', pageParams(query)))
}
export async function listPersonnel(query = {}) {
return normalizeList(await get('/transport/personnel', pageParams(query)))
}
// ── 运费结算 ──
export async function listFreight(query = {}) {
return normalizeList(await get('/transport/freight/', pageParams(query)))
}
export async function getFreight(id) {
return get(`/transport/freight/${String(id)}`)
}
export async function listUnsettledPlans(query = {}) {
return normalizeList(await get('/transport/freight/unsettled-plans', pageParams(query)))
}
export async function createFreight(data) {
return post('/transport/freight/', data)
}
/** 提交审批(需审批人 ID,复杂选人建议 Web;小程序可传已选 ID) */
export async function submitFreightApproval(id, data) {
return post(`/transport/freight/${String(id)}/submit-approval`, data)
}
export async function processFreightApproval(approvalId, data) {
return post(`/transport/freight/approval/${String(approvalId)}`, data)
}
export async function getFreightApprovalFlow(id) {
const data = await get(`/transport/freight/${String(id)}/approval-flow`)
return Array.isArray(data) ? data : []
}