From 493a27022ad30291934db825bab591c7efdcbc09 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Wed, 12 Aug 2026 16:35:45 +0800
Subject: [PATCH] feat: 保存的时候一个按钮置灰
---
packages/utils/common/index.js | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 150 insertions(+), 2 deletions(-)
diff --git a/packages/utils/common/index.js b/packages/utils/common/index.js
index 0c1f904..97ff9a5 100644
--- a/packages/utils/common/index.js
+++ b/packages/utils/common/index.js
@@ -12,9 +12,40 @@
return rules
}
+const isContactPhone = value => {
+ const mobile = /^1[3-9]\d{9}$/
+ const landline = /^0\d{2,3}-?\d{7,8}$/
+ return mobile.test(value) || landline.test(value)
+}
-export function getDictLabel(value, dictList) {
- return dictList.find(item => item.dictKey === value)?.dictValue || value || '-'
+export const contactPhoneRules = (required = true, max = 50) => {
+ const validateContactPhone = (rule, value, callback) => {
+ const nextValue = String(value || '').trim()
+ if (!nextValue) return callback()
+ if (isContactPhone(nextValue)) return callback()
+ return callback(new Error('联系电话格式不正确'))
+ }
+
+ return [...fieldRules(required, max), { validator: validateContactPhone, trigger: ['blur', 'change'] }]
+}
+
+export function getDictLabel(value, dictList = []) {
+ if (value === null || value === undefined || value === '') return '';
+ const values = String(value).split(',');
+ return dictList
+ .filter(item => values.includes(String(item.dictKey)))
+ .map(item => item.dictValue)
+ .join(',');
+}
+
+// id转label xt
+export function getDictLabelXT(value, dictList = []) {
+ if (value === null || value === undefined || value === '') return '';
+ const values = String(value).split(',');
+ return dictList
+ .filter(item => values.includes(String(item.dictValue)))
+ .map(item => item.dictLabel)
+ .join(',');
}
export function blobDownload(res) {
@@ -30,3 +61,120 @@
elink.click()
document.body.removeChild(elink)
}
+
+export function geomAnalysis(str) {
+ if (!str) return []
+ return str
+ .replace('POLYGON((', '')
+ .replace('))', '')
+ .split(',')
+ .map(pair => {
+ const [longitude, latitude] = pair.trim().split(' ').map(Number)
+ return { longitude, latitude }
+ })
+}
+
+// 替换图片请求代理地址
+export function replaceWithProxy(url) {
+ if (!url) return ''
+ return url.replace(
+ /^https?:\/\/[^/]+/,
+ 'https://wrj.shuixiongit.com/ja-proxy'
+ )
+}
+
+// 加载图片并获取原始尺寸
+function loadImage(url) {
+ return new Promise((resolve, reject) => {
+ const image = new Image()
+ image.crossOrigin = 'anonymous'
+ image.onload = () => {
+ if (!image.naturalWidth || !image.naturalHeight) {
+ reject(new Error('图片尺寸无效'))
+ return
+ }
+ resolve(image)
+ }
+ image.onerror = () => reject(new Error('图片加载失败'))
+ image.src = url
+ })
+}
+
+// 在图片上绘制算法框
+function renderAiFrame(image, aiFrame, scaleX = 1, scaleY = 1) {
+ const canvas = document.createElement('canvas')
+ const ctx = canvas.getContext('2d')
+ if (!ctx) return ''
+
+ canvas.width = image.naturalWidth
+ canvas.height = image.naturalHeight
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height)
+
+ aiFrame.forEach(item => {
+ const { x_cen, y_cen, width, height } = item.bbox || {}
+ if ([x_cen, y_cen, width, height].some(value => typeof value !== 'number')) return
+
+ const scaledWidth = width * scaleX
+ const scaledHeight = height * scaleY
+ const x = x_cen * scaleX - scaledWidth / 2
+ const y = y_cen * scaleY - scaledHeight / 2
+ const label = item.class_name || ''
+ const fontSize = Math.max(18, Math.round(canvas.width / 80))
+ const labelHeight = fontSize + 10
+ const labelY = y - labelHeight >= 0 ? y - labelHeight : y
+
+ ctx.strokeStyle = '#FF3B30'
+ ctx.lineWidth = Math.max(3, Math.round(canvas.width / 640))
+ ctx.strokeRect(x, y, scaledWidth, scaledHeight)
+
+ if (label) {
+ ctx.font = `${fontSize}px Arial`
+ const labelWidth = ctx.measureText(label).width + 16
+ ctx.fillStyle = '#FF3B30'
+ ctx.fillRect(x, labelY, labelWidth, labelHeight)
+ ctx.fillStyle = '#FFFFFF'
+ ctx.textBaseline = 'middle'
+ ctx.fillText(label, x + 8, labelY + labelHeight / 2)
+ }
+ })
+
+ try {
+ return canvas.toDataURL('image/jpeg', 0.92)
+ } catch {
+ return ''
+ }
+}
+
+// 异步生成算法成果图片
+export async function appendAiImages(item) {
+ try {
+ const aiFrame = JSON.parse(item.geojson)
+ const resultImagePromise = loadImage(item.resultUrl)
+ const thumbnailImagePromise = loadImage(item.thumbnail).catch(() => null)
+ const resultImage = await resultImagePromise
+ item.resultUrl = renderAiFrame(resultImage, aiFrame)
+ const thumbnailImage = await thumbnailImagePromise
+ if (!thumbnailImage) {
+ item.thumbnail = item.resultUrl
+ return
+ }
+ const scaleX = thumbnailImage.naturalWidth / resultImage.naturalWidth
+ const scaleY = thumbnailImage.naturalHeight / resultImage.naturalHeight
+ item.thumbnail = renderAiFrame(thumbnailImage, aiFrame, scaleX, scaleY)
+ } catch {
+ item.thumbnail = item.resultUrl
+ }
+}
+
+// 图片转带ai框的图片
+export async function drawAiFrame(url, aiFrameSource) {
+ if (!url) return url
+ if (!aiFrameSource) return url
+ try {
+ const aiFrame = JSON.parse(aiFrameSource)
+ const image = await loadImage(url)
+ return renderAiFrame(image, aiFrame)
+ } catch {
+ return ''
+ }
+}
--
Gitblit v1.9.3