2026-06-05 12:28:36 +08:00
|
|
|
|
import { prepareImagePath } from '@/common/js/image-compress.js'
|
2026-06-18 10:20:24 +08:00
|
|
|
|
import { uploadToOss } from '@/common/js/oss-upload.js'
|
2026-06-18 15:05:14 +08:00
|
|
|
|
import { requestGalleryPick } from '@/subPackages/sub_salesperson/common/imageGalleryBridge.js'
|
2026-06-05 12:28:36 +08:00
|
|
|
|
|
2026-06-18 17:04:50 +08:00
|
|
|
|
function basenameFromPath(filePath) {
|
|
|
|
|
|
const pathStr = String(filePath || '')
|
|
|
|
|
|
const parts = pathStr.split(/[/\\]/)
|
|
|
|
|
|
return parts[parts.length - 1] || ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-18 15:05:14 +08:00
|
|
|
|
function chooseImageFromDevice(count = 1) {
|
2026-06-05 12:28:36 +08:00
|
|
|
|
return new Promise((resolve, reject) => {
|
2026-06-18 15:05:14 +08:00
|
|
|
|
uni.showActionSheet({
|
|
|
|
|
|
itemList: ['拍照', '从相册选择'],
|
|
|
|
|
|
success: (sheet) => {
|
|
|
|
|
|
const sourceType = sheet.tapIndex === 0 ? ['camera'] : ['album']
|
|
|
|
|
|
uni.chooseImage({
|
|
|
|
|
|
count,
|
|
|
|
|
|
sizeType: ['original', 'compressed'],
|
|
|
|
|
|
sourceType,
|
|
|
|
|
|
success: (res) => resolve(res),
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
if (err && err.errMsg && err.errMsg.indexOf('cancel') !== -1) {
|
|
|
|
|
|
reject(new Error('cancel'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
reject(err)
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
2026-06-05 12:28:36 +08:00
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
if (err && err.errMsg && err.errMsg.indexOf('cancel') !== -1) {
|
|
|
|
|
|
reject(new Error('cancel'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
reject(err)
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-18 15:05:14 +08:00
|
|
|
|
async function uploadChosenImages(res, count = 1) {
|
|
|
|
|
|
uni.showLoading({ title: '上传中...', mask: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
const files = res.tempFiles || []
|
|
|
|
|
|
const paths = files.length ? files.map((f) => f.path) : (res.tempFilePaths || [])
|
|
|
|
|
|
const urls = []
|
|
|
|
|
|
for (const path of paths) {
|
2026-06-18 17:04:50 +08:00
|
|
|
|
const fileMeta = files.find((f) => f.path === path) || {};
|
2026-06-18 15:05:14 +08:00
|
|
|
|
const prepared = await prepareImagePath({
|
|
|
|
|
|
path,
|
2026-06-18 17:04:50 +08:00
|
|
|
|
size: fileMeta.size,
|
2026-06-18 15:05:14 +08:00
|
|
|
|
})
|
|
|
|
|
|
if (!prepared) continue
|
2026-06-18 17:04:50 +08:00
|
|
|
|
const fileSize = fileMeta.size || 0
|
|
|
|
|
|
const fileName = fileMeta.name || basenameFromPath(path)
|
|
|
|
|
|
const result = await uploadToOss({ filePath: prepared.path, fileSize, fileName })
|
2026-06-18 15:05:14 +08:00
|
|
|
|
urls.push(result.url)
|
|
|
|
|
|
}
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
if (!urls.length) throw new Error('上传失败')
|
|
|
|
|
|
return count === 1 ? urls[0] : urls
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
uni.showToast({ title: e.message || '上传失败', icon: 'none' })
|
|
|
|
|
|
throw e
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 打开图库选择(由页面内 link 单独触发)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function openGalleryPick() {
|
|
|
|
|
|
return requestGalleryPick()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 选择并上传图片(压缩 + OSS 直传)
|
|
|
|
|
|
* @param {{ count?: number }} options count>1 时依次上传多张,返回 url 数组
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function pickAndUploadImage(options = {}) {
|
|
|
|
|
|
const count = Math.min(Math.max(options.count || 1, 1), 9)
|
|
|
|
|
|
return chooseImageFromDevice(count)
|
|
|
|
|
|
.then((res) => uploadChosenImages(res, count))
|
|
|
|
|
|
.catch((err) => Promise.reject(err))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-05 12:28:36 +08:00
|
|
|
|
function getUserDataPath() {
|
|
|
|
|
|
if (typeof wx !== 'undefined' && wx.env && wx.env.USER_DATA_PATH) {
|
|
|
|
|
|
return wx.env.USER_DATA_PATH
|
|
|
|
|
|
}
|
|
|
|
|
|
if (uni.env && uni.env.USER_DATA_PATH) {
|
|
|
|
|
|
return uni.env.USER_DATA_PATH
|
|
|
|
|
|
}
|
|
|
|
|
|
return ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function uploadSignFilePath(filePath) {
|
2026-06-18 10:20:24 +08:00
|
|
|
|
const result = await uploadToOss({ filePath })
|
|
|
|
|
|
if (!result || !result.url) {
|
2026-06-05 12:28:36 +08:00
|
|
|
|
throw new Error('上传成功但未返回地址')
|
|
|
|
|
|
}
|
2026-06-18 10:20:24 +08:00
|
|
|
|
return result.url
|
2026-06-05 12:28:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 手写签名 canvas 临时文件直传 OSS
|
|
|
|
|
|
* @param {string} tempFilePath canvasToTempFilePath 路径
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function uploadSignCanvasTempPath(tempFilePath) {
|
|
|
|
|
|
return new Promise(async (resolve, reject) => {
|
|
|
|
|
|
if (!tempFilePath) {
|
|
|
|
|
|
reject(new Error('签名为空'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
uni.showLoading({ title: '上传中...', mask: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
const url = await uploadSignFilePath(tempFilePath)
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
resolve(url)
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
reject(e)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 手写签名板 base64 写入临时文件后上传 OSS
|
|
|
|
|
|
* @param {string} base64 canvas 导出的 base64(可带 data:image 前缀)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function uploadSignCanvasBase64(base64) {
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
if (!base64) {
|
|
|
|
|
|
reject(new Error('签名为空'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const root = getUserDataPath()
|
|
|
|
|
|
if (!root) {
|
|
|
|
|
|
reject(new Error('无法获取临时目录'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const fs = uni.getFileSystemManager()
|
|
|
|
|
|
const filePath = `${root}/sign_${Date.now()}.png`
|
|
|
|
|
|
const data = String(base64).replace(/^data:image\/\w+;base64,/, '')
|
|
|
|
|
|
fs.writeFile({
|
|
|
|
|
|
filePath,
|
|
|
|
|
|
data,
|
|
|
|
|
|
encoding: 'base64',
|
|
|
|
|
|
success: async () => {
|
|
|
|
|
|
uni.showLoading({ title: '上传中...', mask: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
const url = await uploadSignFilePath(filePath)
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
resolve(url)
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
reject(e)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: () => reject(new Error('签名临时文件写入失败')),
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function createDefaultStoreInputForm() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
contact: '',
|
|
|
|
|
|
mobile: '',
|
|
|
|
|
|
code: '',
|
|
|
|
|
|
position: '',
|
|
|
|
|
|
province_id: null,
|
|
|
|
|
|
city_id: null,
|
2026-06-18 10:52:42 +08:00
|
|
|
|
clinic_type: 1,
|
2026-06-05 12:28:36 +08:00
|
|
|
|
type: 0,
|
|
|
|
|
|
is_shipping_free: 0,
|
|
|
|
|
|
subscribe_price_change: 0,
|
|
|
|
|
|
start_time: '08:00',
|
|
|
|
|
|
end_time: '20:00',
|
|
|
|
|
|
see_rate: '',
|
|
|
|
|
|
url: [],
|
|
|
|
|
|
contract_files: [],
|
|
|
|
|
|
z_buy_percent: 100,
|
|
|
|
|
|
z_sale_percent: 100,
|
|
|
|
|
|
bank_user_name: '',
|
|
|
|
|
|
bank_card: '',
|
|
|
|
|
|
bank_name: '',
|
|
|
|
|
|
bank_no: '',
|
|
|
|
|
|
bank_account_type: 1,
|
|
|
|
|
|
address: [],
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function createDefaultDoctorInputForm() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
mobile: '',
|
|
|
|
|
|
idcard: '',
|
|
|
|
|
|
avatar: '',
|
|
|
|
|
|
depart_id: null,
|
|
|
|
|
|
title_id: null,
|
|
|
|
|
|
type: 1,
|
|
|
|
|
|
sign_type: 1,
|
|
|
|
|
|
good_at: '',
|
|
|
|
|
|
intro: '',
|
|
|
|
|
|
qualification: '',
|
|
|
|
|
|
practicing: '',
|
|
|
|
|
|
title: '',
|
|
|
|
|
|
card_up: '',
|
|
|
|
|
|
card_down: '',
|
|
|
|
|
|
sign_image: '',
|
2026-06-18 15:05:14 +08:00
|
|
|
|
register_price: 0,
|
2026-06-05 12:28:36 +08:00
|
|
|
|
store_id: 0,
|
|
|
|
|
|
store_ids: [],
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|