139 lines
3.8 KiB
JavaScript
139 lines
3.8 KiB
JavaScript
import { useUserStore } from '@/store'
|
||
|
||
export const baseUrl = 'https://lygcgs.com.cn:8078/shjapi/api/'
|
||
export const baseFileUrl = 'https://lygcgs.com.cn:8078/shj/'
|
||
|
||
/**
|
||
* 将参数对象序列化为 URL query string
|
||
* 手动构建确保跨平台(小程序 / H5 / App)行为一致
|
||
* - 过滤 undefined 和 null
|
||
* - encodeURIComponent 编码中文和特殊字符
|
||
*/
|
||
function toQueryString(params) {
|
||
if (!params) return ''
|
||
const parts = Object.keys(params)
|
||
.filter((k) => params[k] !== undefined && params[k] !== null)
|
||
.map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
|
||
return parts.length ? '?' + parts.join('&') : ''
|
||
}
|
||
|
||
/**
|
||
* 核心请求方法(兼容 小程序 / H5 / App)
|
||
*
|
||
* @param {string} url - API 路径(不含 baseUrl)
|
||
* @param {object} options - 可选配置
|
||
* {string} method - GET | POST,默认 GET
|
||
* {object} data - GET 时自动拼入 query string,POST 时作为请求体
|
||
* {object} header - 自定义请求头
|
||
* {boolean} loading - 是否显示 loading,默认 true
|
||
* {boolean} toast - 是否在失败时弹 toast,默认 true
|
||
*/
|
||
export function request(url, options) {
|
||
const opts = options || {}
|
||
const method = opts.method || 'GET'
|
||
const data = opts.data
|
||
const header = opts.header || {}
|
||
const loading = opts.loading !== false
|
||
const toast = opts.toast !== false
|
||
|
||
const userStore = useUserStore()
|
||
const headers = {
|
||
'content-type': 'application/json',
|
||
...header
|
||
}
|
||
if (userStore.token) {
|
||
headers.token = userStore.token
|
||
}
|
||
|
||
// GET: 手动拼 query string(不依赖 uni.request 各平台差异)
|
||
let fullUrl = baseUrl + url
|
||
if (method === 'GET' && data) {
|
||
fullUrl = fullUrl + toQueryString(data)
|
||
}
|
||
|
||
if (loading) {
|
||
uni.showLoading({ title: '加载中...', mask: true })
|
||
}
|
||
|
||
return new Promise(function (resolve, reject) {
|
||
uni.request({
|
||
url: fullUrl,
|
||
method: method,
|
||
data: method === 'POST' ? data : undefined,
|
||
header: headers,
|
||
success: function (res) {
|
||
if (loading) uni.hideLoading()
|
||
const body = res.data
|
||
if (body.code !== 1) {
|
||
if (toast) {
|
||
uni.showToast({
|
||
title: body.message || '请求失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
if (body.code === 401) {
|
||
userStore.logout()
|
||
uni.reLaunch({ url: '/pages/login/index' })
|
||
}
|
||
reject(new Error(body.message || '请求失败'))
|
||
return
|
||
}
|
||
resolve(body)
|
||
},
|
||
fail: function (err) {
|
||
if (loading) uni.hideLoading()
|
||
uni.showToast({ title: '网络连接失败', icon: 'none' })
|
||
reject(err)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
/**
|
||
* GET 快捷方法
|
||
* 兼容两种调用方式:
|
||
* get('/path?key=val') 旧风格(URL 自带参数)
|
||
* get('/path', { key: 'val' }) 新风格(参数对象,自动编码)
|
||
*/
|
||
export function get(url, params) {
|
||
let fullUrl = url
|
||
if (params) {
|
||
fullUrl = url + toQueryString(params)
|
||
}
|
||
return request(fullUrl, { method: 'GET' })
|
||
}
|
||
|
||
/**
|
||
* POST 快捷方法
|
||
*/
|
||
export function post(url, data) {
|
||
return request(url, { method: 'POST', data: data })
|
||
}
|
||
|
||
/**
|
||
* 解析附件 URL 字符串为可展示的照片列表
|
||
* @param {string} urlStr - 逗号分隔的附件路径,如 "FileUpLoad/xxx.png,FileUpLoad/yyy.png"
|
||
* @param {number} startId - 起始 ID,用于生成唯一标识
|
||
* @returns {Array<{_id: number, src: string, uploaded: boolean}>}
|
||
*/
|
||
export const parseAttachUrls = (urlStr, startId = 0) => {
|
||
if (!urlStr) return []
|
||
let id = startId
|
||
return urlStr.split(',').filter(Boolean).map((url) => ({
|
||
_id: ++id,
|
||
src: `${baseFileUrl}${url}`,
|
||
_attachUrl: url,
|
||
uploaded: true
|
||
}))
|
||
}
|
||
|
||
export const getUrlParam = (url, name) => {
|
||
if (!url || !name) return null
|
||
const regex = new RegExp(`[?&]${name}=([^&]*)`, 'i')
|
||
const match = url.match(regex)
|
||
if (match && match[1]) {
|
||
return decodeURIComponent(match[1])
|
||
}
|
||
return null
|
||
}
|