hookehuyr

chore: 迁移TypeScript工具函数至JavaScript并更新配置

- 将PosterBuilder组件的工具函数从TypeScript迁移至JavaScript以简化构建
- 修复ESLint配置,添加root标志防止继承外部规则
- 更新package.json添加lint脚本便于代码检查
- 优化API响应处理函数,增强错误处理和类型安全
- 调整环境配置,将生产环境指向开发服务器
1 // ESLint 检查 .vue 文件需要单独配置编辑器: 1 // ESLint 检查 .vue 文件需要单独配置编辑器:
2 // https://eslint.vuejs.org/user-guide/#editor-integrations 2 // https://eslint.vuejs.org/user-guide/#editor-integrations
3 { 3 {
4 + "root": true,
4 "extends": ["taro/vue3"], 5 "extends": ["taro/vue3"],
5 "parserOptions": { 6 "parserOptions": {
6 "requireConfigFile": false 7 "requireConfigFile": false
......
...@@ -26,7 +26,8 @@ ...@@ -26,7 +26,8 @@
26 "dev:rn": "NODE_ENV=development taro build --type rn --watch", 26 "dev:rn": "NODE_ENV=development taro build --type rn --watch",
27 "dev:qq": "NODE_ENV=development taro build --type qq --watch", 27 "dev:qq": "NODE_ENV=development taro build --type qq --watch",
28 "dev:quickapp": "NODE_ENV=development taro build --type quickapp --watch", 28 "dev:quickapp": "NODE_ENV=development taro build --type quickapp --watch",
29 - "postinstall": "weapp-tw patch" 29 + "postinstall": "weapp-tw patch",
30 + "lint": "eslint --ext .js,.vue src"
30 }, 31 },
31 "browserslist": [ 32 "browserslist": [
32 "last 3 versions", 33 "last 3 versions",
......
1 /* 1 /*
2 * @Date: 2022-05-18 22:56:08 2 * @Date: 2022-05-18 22:56:08
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-20 11:47:29 4 + * @LastEditTime: 2026-01-24 12:13:14
5 * @FilePath: /xyxBooking-weapp/src/api/fn.js 5 * @FilePath: /xyxBooking-weapp/src/api/fn.js
6 * @Description: 文件描述 6 * @Description: 文件描述
7 */ 7 */
...@@ -18,24 +18,24 @@ export const fn = (api) => { ...@@ -18,24 +18,24 @@ export const fn = (api) => {
18 return api 18 return api
19 .then(res => { 19 .then(res => {
20 // 适配 H5 逻辑,code === 1 为成功 20 // 适配 H5 逻辑,code === 1 为成功
21 - if (res.data.code == 1) { 21 + const res_data = res && res.data ? res.data : null
22 - return res.data || true; 22 + if (res_data && String(res_data.code) === '1') {
23 - } else { 23 + return res_data
24 + }
24 // tslint:disable-next-line: no-console 25 // tslint:disable-next-line: no-console
25 - console.warn('API Error:', res); 26 + console.warn('API Error:', res)
26 - if (res.data.show === false) return false; 27 + if (res_data && res_data.show === false) return res_data
27 Taro.showToast({ 28 Taro.showToast({
28 - title: res.data.msg || '请求失败', 29 + title: (res_data && res_data.msg) ? res_data.msg : '请求失败',
29 icon: 'none', 30 icon: 'none',
30 duration: 2000 31 duration: 2000
31 - }); 32 + })
32 - return res.data || false; 33 + return res_data || { code: 0, data: null, msg: '请求失败' }
33 - }
34 }) 34 })
35 .catch(err => { 35 .catch(err => {
36 // tslint:disable-next-line: no-console 36 // tslint:disable-next-line: no-console
37 console.error(err); 37 console.error(err);
38 - return false; 38 + return { code: 0, data: null, msg: (err && (err.msg || err.message || err.errMsg)) ? (err.msg || err.message || err.errMsg) : '网络异常' }
39 }) 39 })
40 .finally(() => { // 最终执行 40 .finally(() => { // 最终执行
41 }) 41 })
......
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
10 <script> 10 <script>
11 import Taro from "@tarojs/taro" 11 import Taro from "@tarojs/taro"
12 import { defineComponent, onMounted, ref } from "vue" 12 import { defineComponent, onMounted, ref } from "vue"
13 -import { drawImage, drawText, drawBlock, drawLine } from "./utils/draw" 13 +import { drawImage, drawText, drawBlock, drawLine } from "./utils/draw.js"
14 import { 14 import {
15 toPx, 15 toPx,
16 toRpx, 16 toRpx,
17 getRandomId, 17 getRandomId,
18 getImageInfo, 18 getImageInfo,
19 getLinearColor, 19 getLinearColor,
20 -} from "./utils/tools" 20 +} from "./utils/tools.js"
21 21
22 export default defineComponent({ 22 export default defineComponent({
23 name: "PosterBuilder", 23 name: "PosterBuilder",
......
1 -export type DrawType = 'text' | 'image' | 'block' | 'line';
2 -
3 -export interface Block {
4 - type?: DrawType;
5 - x: number;
6 - y: number;
7 - width?: number;
8 - height: number;
9 - paddingLeft?: number;
10 - paddingRight?: number;
11 - borderWidth?: number;
12 - borderColor?: string;
13 - backgroundColor?: string;
14 - borderRadius?: number;
15 - borderRadiusGroup?: number[];
16 - text?: Text;
17 - opacity?: number;
18 - zIndex?: number;
19 -}
20 -
21 -export interface Text {
22 - type?: DrawType;
23 - x?: number;
24 - y?: number;
25 - text: string | Text[];
26 - fontSize?: number;
27 - color?: string;
28 - opacity?: 1 | 0;
29 - lineHeight?: number;
30 - lineNum?: number;
31 - width?: number;
32 - marginTop?: number;
33 - marginLeft?: number;
34 - marginRight?: number;
35 - textDecoration?: 'line-through' | 'none';
36 - baseLine?: 'top' | 'middle' | 'bottom';
37 - textAlign?: 'left' | 'center' | 'right';
38 - fontFamily?: string;
39 - fontWeight?: string;
40 - fontStyle?: string;
41 - zIndex?: number;
42 -}
43 -
44 -export interface Image {
45 - type?: DrawType;
46 - x: number;
47 - y: number;
48 - url: string;
49 - width: number;
50 - height: number;
51 - borderRadius?: number;
52 - borderRadiusGroup?: number[];
53 - borderWidth?: number;
54 - borderColor?: string;
55 - zIndex?: number;
56 -}
57 -
58 -export interface Line {
59 - type?: DrawType;
60 - startX: number;
61 - startY: number;
62 - endX: number;
63 - endY: number;
64 - width: number;
65 - color?: string;
66 - zIndex?: number;
67 -}
68 -
69 -export type DrawConfig = {
70 - width: number;
71 - height: number;
72 - backgroundColor?: string;
73 - debug?: boolean;
74 - blocks?: Block[];
75 - texts?: Text[];
76 - images?: Image[];
77 - lines?: Line[];
78 -};
1 +import { getLinearColor, getTextX, toPx } from './tools'
2 +
3 +const drawRadiusRect = ({ x, y, w, h, r }, { ctx }) => {
4 + const minSize = Math.min(w, h)
5 + if (r > minSize / 2) r = minSize / 2
6 + ctx.beginPath()
7 + ctx.moveTo(x + r, y)
8 + ctx.arcTo(x + w, y, x + w, y + h, r)
9 + ctx.arcTo(x + w, y + h, x, y + h, r)
10 + ctx.arcTo(x, y + h, x, y, r)
11 + ctx.arcTo(x, y, x + w, y, r)
12 + ctx.closePath()
13 +}
14 +
15 +const drawRadiusGroupRect = ({ x, y, w, h, g }, { ctx }) => {
16 + const [
17 + borderTopLeftRadius,
18 + borderTopRightRadius,
19 + borderBottomRightRadius,
20 + borderBottomLeftRadius
21 + ] = g
22 + ctx.beginPath()
23 + ctx.arc(
24 + x + w - borderBottomRightRadius,
25 + y + h - borderBottomRightRadius,
26 + borderBottomRightRadius,
27 + 0,
28 + Math.PI * 0.5
29 + )
30 + ctx.lineTo(x + borderBottomLeftRadius, y + h)
31 + ctx.arc(
32 + x + borderBottomLeftRadius,
33 + y + h - borderBottomLeftRadius,
34 + borderBottomLeftRadius,
35 + Math.PI * 0.5,
36 + Math.PI
37 + )
38 + ctx.lineTo(x, y + borderTopLeftRadius)
39 + ctx.arc(
40 + x + borderTopLeftRadius,
41 + y + borderTopLeftRadius,
42 + borderTopLeftRadius,
43 + Math.PI,
44 + Math.PI * 1.5
45 + )
46 + ctx.lineTo(x + w - borderTopRightRadius, y)
47 + ctx.arc(
48 + x + w - borderTopRightRadius,
49 + y + borderTopRightRadius,
50 + borderTopRightRadius,
51 + Math.PI * 1.5,
52 + Math.PI * 2
53 + )
54 + ctx.lineTo(x + w, y + h - borderBottomRightRadius)
55 + ctx.closePath()
56 +}
57 +
58 +const getTextWidth = (text, drawOptions) => {
59 + const { ctx } = drawOptions
60 + let texts = []
61 + if (Object.prototype.toString.call(text) === '[object Object]') {
62 + texts.push(text)
63 + } else {
64 + texts = text
65 + }
66 + let width = 0
67 + texts.forEach(
68 + ({
69 + fontSize,
70 + text: textStr,
71 + fontStyle = 'normal',
72 + fontWeight = 'normal',
73 + fontFamily = 'sans-serif',
74 + marginLeft = 0,
75 + marginRight = 0
76 + }) => {
77 + ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`
78 + width += ctx.measureText(textStr).width + marginLeft + marginRight
79 + }
80 + )
81 + return width
82 +}
83 +
84 +const drawSingleText = (drawData, drawOptions) => {
85 + const {
86 + x = 0,
87 + y = 0,
88 + text,
89 + color,
90 + width,
91 + fontSize = 28,
92 + baseLine = 'top',
93 + textAlign = 'left',
94 + opacity = 1,
95 + textDecoration = 'none',
96 + lineNum = 1,
97 + lineHeight = 0,
98 + fontWeight = 'normal',
99 + fontStyle = 'normal',
100 + fontFamily = 'sans-serif'
101 + } = drawData
102 + const { ctx } = drawOptions
103 + ctx.save()
104 + ctx.beginPath()
105 + ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`
106 + ctx.globalAlpha = opacity
107 + ctx.fillStyle = color
108 + ctx.textBaseline = baseLine
109 + ctx.textAlign = textAlign
110 + let textWidth = ctx.measureText(text).width
111 + const textArr = []
112 +
113 + if (textWidth > width) {
114 + let fillText = ''
115 + let line = 1
116 + for (let i = 0; i <= text.length - 1; i++) {
117 + fillText += text[i]
118 + const nextText = i < text.length - 1 ? fillText + text[i + 1] : fillText
119 + const restWidth = width - ctx.measureText(nextText).width
120 +
121 + if (restWidth < 0) {
122 + if (line === lineNum) {
123 + if (
124 + restWidth + ctx.measureText(text[i + 1]).width >
125 + ctx.measureText('...').width
126 + ) {
127 + fillText = `${fillText}...`
128 + } else {
129 + fillText = `${fillText.substr(0, fillText.length - 1)}...`
130 + }
131 + textArr.push(fillText)
132 + break
133 + } else {
134 + textArr.push(fillText)
135 + line++
136 + fillText = ''
137 + }
138 + } else if (i === text.length - 1) {
139 + textArr.push(fillText)
140 + }
141 + }
142 + textWidth = width
143 + } else {
144 + textArr.push(text)
145 + }
146 +
147 + textArr.forEach((item, index) =>
148 + ctx.fillText(
149 + item,
150 + getTextX(textAlign, x, width),
151 + y + (lineHeight || fontSize) * index
152 + )
153 + )
154 + ctx.restore()
155 +
156 + if (textDecoration !== 'none') {
157 + let lineY = y
158 + if (textDecoration === 'line-through') {
159 + lineY = y
160 + }
161 + ctx.save()
162 + ctx.moveTo(x, lineY)
163 + ctx.lineTo(x + textWidth, lineY)
164 + ctx.strokeStyle = color
165 + ctx.stroke()
166 + ctx.restore()
167 + }
168 + return textWidth
169 +}
170 +
171 +export function drawText(params, drawOptions) {
172 + const { x = 0, y = 0, text, baseLine } = params
173 + if (Object.prototype.toString.call(text) === '[object Array]') {
174 + const preText = { x, y, baseLine }
175 + text.forEach((item) => {
176 + preText.x += item.marginLeft || 0
177 + const textWidth = drawSingleText(
178 + Object.assign(item, { ...preText, y: y + (item.marginTop || 0) }),
179 + drawOptions
180 + )
181 + preText.x += textWidth + (item.marginRight || 0)
182 + })
183 + } else {
184 + drawSingleText(params, drawOptions)
185 + }
186 +}
187 +
188 +export function drawLine(drawData, drawOptions) {
189 + const { startX, startY, endX, endY, color, width } = drawData
190 + const { ctx } = drawOptions
191 + if (!width) return
192 + ctx.save()
193 + ctx.beginPath()
194 + ctx.strokeStyle = color
195 + ctx.lineWidth = width
196 + ctx.moveTo(startX, startY)
197 + ctx.lineTo(endX, endY)
198 + ctx.stroke()
199 + ctx.closePath()
200 + ctx.restore()
201 +}
202 +
203 +export function drawBlock(data, drawOptions) {
204 + const {
205 + x,
206 + y,
207 + text,
208 + width = 0,
209 + height,
210 + opacity = 1,
211 + paddingLeft = 0,
212 + paddingRight = 0,
213 + borderWidth,
214 + backgroundColor,
215 + borderColor,
216 + borderRadius = 0,
217 + borderRadiusGroup = null
218 + } = data || {}
219 + const { ctx } = drawOptions
220 + ctx.save()
221 + ctx.globalAlpha = opacity
222 +
223 + let blockWidth = 0
224 + let textX = 0
225 + let textY = 0
226 +
227 + if (text) {
228 + const textWidth = getTextWidth(
229 + typeof text.text === 'string' ? text : text.text,
230 + drawOptions
231 + )
232 + blockWidth = textWidth > width ? textWidth : width
233 + blockWidth += paddingLeft + paddingLeft
234 +
235 + const { textAlign = 'left' } = text
236 + textY = y
237 + textX = x + paddingLeft
238 +
239 + if (textAlign === 'center') {
240 + textX = blockWidth / 2 + x
241 + } else if (textAlign === 'right') {
242 + textX = x + blockWidth - paddingRight
243 + }
244 + drawText(Object.assign(text, { x: textX, y: textY }), drawOptions)
245 + } else {
246 + blockWidth = width
247 + }
248 +
249 + if (backgroundColor) {
250 + const grd = getLinearColor(ctx, backgroundColor, x, y, blockWidth, height)
251 + ctx.fillStyle = grd
252 +
253 + if (borderRadius > 0) {
254 + const drawData = {
255 + x,
256 + y,
257 + w: blockWidth,
258 + h: height,
259 + r: borderRadius
260 + }
261 + drawRadiusRect(drawData, drawOptions)
262 + ctx.fill()
263 + } else if (borderRadiusGroup) {
264 + const drawData = {
265 + x,
266 + y,
267 + w: blockWidth,
268 + h: height,
269 + g: borderRadiusGroup
270 + }
271 + drawRadiusGroupRect(drawData, drawOptions)
272 + ctx.fill()
273 + } else {
274 + ctx.fillRect(x, y, blockWidth, height)
275 + }
276 + }
277 +
278 + if (borderWidth && borderRadius > 0) {
279 + ctx.strokeStyle = borderColor
280 + ctx.lineWidth = borderWidth
281 + if (borderRadius > 0) {
282 + const drawData = {
283 + x,
284 + y,
285 + w: blockWidth,
286 + h: height,
287 + r: borderRadius
288 + }
289 + drawRadiusRect(drawData, drawOptions)
290 + ctx.stroke()
291 + } else {
292 + ctx.strokeRect(x, y, blockWidth, height)
293 + }
294 + }
295 + ctx.restore()
296 +}
297 +
298 +export const drawImage = (data, drawOptions) =>
299 + new Promise((resolve) => {
300 + const { canvas, ctx } = drawOptions
301 + const {
302 + x,
303 + y,
304 + w,
305 + h,
306 + sx,
307 + sy,
308 + sw,
309 + sh,
310 + imgPath,
311 + borderRadius = 0,
312 + borderWidth = 0,
313 + borderColor,
314 + borderRadiusGroup = null
315 + } = data
316 +
317 + ctx.save()
318 + if (borderRadius > 0) {
319 + drawRadiusRect(
320 + {
321 + x,
322 + y,
323 + w,
324 + h,
325 + r: borderRadius
326 + },
327 + drawOptions
328 + )
329 + ctx.clip()
330 + ctx.fill()
331 + const img = canvas.createImage()
332 + img.src = imgPath
333 + img.onload = () => {
334 + ctx.drawImage(img, toPx(sx), toPx(sy), toPx(sw), toPx(sh), x, y, w, h)
335 + if (borderWidth > 0) {
336 + ctx.strokeStyle = borderColor
337 + ctx.lineWidth = borderWidth
338 + ctx.stroke()
339 + }
340 + resolve()
341 + ctx.restore()
342 + }
343 + } else if (borderRadiusGroup) {
344 + drawRadiusGroupRect(
345 + {
346 + x,
347 + y,
348 + w,
349 + h,
350 + g: borderRadiusGroup
351 + },
352 + drawOptions
353 + )
354 + ctx.clip()
355 + ctx.fill()
356 + const img = canvas.createImage()
357 + img.src = imgPath
358 + img.onload = () => {
359 + ctx.drawImage(img, toPx(sx), toPx(sy), toPx(sw), toPx(sh), x, y, w, h)
360 + resolve()
361 + ctx.restore()
362 + }
363 + } else {
364 + const img = canvas.createImage()
365 + img.src = imgPath
366 + img.onload = () => {
367 + ctx.drawImage(img, toPx(sx), toPx(sy), toPx(sw), toPx(sh), x, y, w, h)
368 + resolve()
369 + ctx.restore()
370 + }
371 + }
372 + })
This diff is collapsed. Click to expand it.
1 +import Taro from '@tarojs/taro'
2 +
3 +export function randomString(length) {
4 + let str = Math.random().toString(36).substr(2)
5 + if (str.length >= length) {
6 + return str.substr(0, length)
7 + }
8 + str += randomString(length - str.length)
9 + return str
10 +}
11 +
12 +export function getRandomId(prefix = 'canvas', length = 10) {
13 + return prefix + randomString(length)
14 +}
15 +
16 +export function mapHttpToHttps(rawUrl) {
17 + if (rawUrl.indexOf(':') < 0 || rawUrl.startsWith('http://tmp')) {
18 + return rawUrl
19 + }
20 + const urlComponent = rawUrl.split(':')
21 + if (urlComponent.length === 2) {
22 + if (urlComponent[0] === 'http') {
23 + urlComponent[0] = 'https'
24 + return `${urlComponent[0]}:${urlComponent[1]}`
25 + }
26 + }
27 + return rawUrl
28 +}
29 +
30 +export const getFactor = () => {
31 + const sysInfo = Taro.getSystemInfoSync()
32 + const { screenWidth } = sysInfo
33 + return screenWidth / 750
34 +}
35 +
36 +export const toPx = (rpx, factor = getFactor()) =>
37 + parseInt(String(rpx * factor), 10)
38 +
39 +export const toRpx = (px, factor = getFactor()) =>
40 + parseInt(String(px / factor), 10)
41 +
42 +export function downImage(url) {
43 + return new Promise((resolve, reject) => {
44 + const wx_user_data_path =
45 + (typeof wx !== 'undefined' && wx && wx.env && wx.env.USER_DATA_PATH)
46 + ? wx.env.USER_DATA_PATH
47 + : ''
48 + const is_local_user_path = wx_user_data_path
49 + ? new RegExp(wx_user_data_path).test(url)
50 + : false
51 +
52 + if (/^http/.test(url) && !is_local_user_path) {
53 + Taro.downloadFile({
54 + url: mapHttpToHttps(url),
55 + success: (res) => {
56 + if (res.statusCode === 200) {
57 + resolve(res.tempFilePath)
58 + } else {
59 + reject(res)
60 + }
61 + },
62 + fail(err) {
63 + reject(err)
64 + }
65 + })
66 + } else {
67 + resolve(url)
68 + }
69 + })
70 +}
71 +
72 +export const getImageInfo = (item, index) =>
73 + new Promise((resolve, reject) => {
74 + const { x, y, width, height, url, zIndex } = item
75 + downImage(url).then((imgPath) =>
76 + Taro.getImageInfo({ src: imgPath })
77 + .then((imgInfo) => {
78 + let sx
79 + let sy
80 + const borderRadius = item.borderRadius || 0
81 + const imgWidth = toRpx(imgInfo.width)
82 + const imgHeight = toRpx(imgInfo.height)
83 + if (imgWidth / imgHeight <= width / height) {
84 + sx = 0
85 + sy = (imgHeight - (imgWidth / width) * height) / 2
86 + } else {
87 + sy = 0
88 + sx = (imgWidth - (imgHeight / height) * width) / 2
89 + }
90 + const result = {
91 + type: 'image',
92 + borderRadius,
93 + borderWidth: item.borderWidth,
94 + borderColor: item.borderColor,
95 + borderRadiusGroup: item.borderRadiusGroup,
96 + zIndex: typeof zIndex !== 'undefined' ? zIndex : index,
97 + imgPath: url,
98 + sx,
99 + sy,
100 + sw: imgWidth - sx * 2,
101 + sh: imgHeight - sy * 2,
102 + x,
103 + y,
104 + w: width,
105 + h: height
106 + }
107 + resolve(result)
108 + })
109 + .catch((err) => {
110 + reject(err)
111 + })
112 + )
113 + })
114 +
115 +export function getLinearColor(ctx, color, startX, startY, w, h) {
116 + if (
117 + typeof startX !== 'number' ||
118 + typeof startY !== 'number' ||
119 + typeof w !== 'number' ||
120 + typeof h !== 'number'
121 + ) {
122 + return color
123 + }
124 + let grd = color
125 + if (color.includes('linear-gradient')) {
126 + const colorList = color.match(/\((\d+)deg,\s(.+)\s\d+%,\s(.+)\s\d+%/)
127 + const radian = colorList[1]
128 + const color1 = colorList[2]
129 + const color2 = colorList[3]
130 +
131 + const L = Math.sqrt(w * w + h * h)
132 + const x = Math.ceil(Math.sin(180 - radian) * L)
133 + const y = Math.ceil(Math.cos(180 - radian) * L)
134 +
135 + if (Number(radian) === 180 || Number(radian) === 0) {
136 + if (Number(radian) === 180) {
137 + grd = ctx.createLinearGradient(startX, startY, startX, startY + h)
138 + }
139 + if (Number(radian) === 0) {
140 + grd = ctx.createLinearGradient(startX, startY + h, startX, startY)
141 + }
142 + } else if (radian > 0 && radian < 180) {
143 + grd = ctx.createLinearGradient(startX, startY, x + startX, y + startY)
144 + } else {
145 + throw new Error('只支持0 <= 颜色弧度 <= 180')
146 + }
147 + grd.addColorStop(0, color1)
148 + grd.addColorStop(1, color2)
149 + }
150 + return grd
151 +}
152 +
153 +export function getTextX(textAlign, x, width) {
154 + let newX = x
155 + if (textAlign === 'center') {
156 + newX = width / 2 + x
157 + } else if (textAlign === 'right') {
158 + newX = width + x
159 + }
160 + return newX
161 +}
1 -/* eslint-disable prefer-destructuring */
2 -import Taro, { CanvasContext, CanvasGradient } from '@tarojs/taro';
3 -
4 -declare const wx: any;
5 -
6 -/**
7 - * @description 生成随机字符串
8 - * @param { number } length - 字符串长度
9 - * @returns { string }
10 - */
11 -export function randomString(length) {
12 - let str = Math.random().toString(36).substr(2);
13 - if (str.length >= length) {
14 - return str.substr(0, length);
15 - }
16 - str += randomString(length - str.length);
17 - return str;
18 -}
19 -
20 -/**
21 - * 随机创造一个id
22 - * @param { number } length - 字符串长度
23 - * @returns { string }
24 - */
25 -export function getRandomId(prefix = 'canvas', length = 10) {
26 - return prefix + randomString(length);
27 -}
28 -
29 -/**
30 - * @description 获取最大高度
31 - * @param {} config
32 - * @returns { number }
33 - */
34 -// export function getHeight (config) {
35 -// const getTextHeight = text => {
36 -// const fontHeight = text.lineHeight || text.fontSize
37 -// let height = 0
38 -// if (text.baseLine === 'top') {
39 -// height = fontHeight
40 -// } else if (text.baseLine === 'middle') {
41 -// height = fontHeight / 2
42 -// } else {
43 -// height = 0
44 -// }
45 -// return height
46 -// }
47 -// const heightArr: number[] = [];
48 -// (config.blocks || []).forEach(item => {
49 -// heightArr.push(item.y + item.height)
50 -// });
51 -// (config.texts || []).forEach(item => {
52 -// let height
53 -// if (Object.prototype.toString.call(item.text) === '[object Array]') {
54 -// item.text.forEach(i => {
55 -// height = getTextHeight({ ...i, baseLine: item.baseLine })
56 -// heightArr.push(item.y + height)
57 -// })
58 -// } else {
59 -// height = getTextHeight(item)
60 -// heightArr.push(item.y + height)
61 -// }
62 -// });
63 -// (config.images || []).forEach(item => {
64 -// heightArr.push(item.y + item.height)
65 -// });
66 -// (config.lines || []).forEach(item => {
67 -// heightArr.push(item.startY)
68 -// heightArr.push(item.endY)
69 -// })
70 -// const sortRes = heightArr.sort((a, b) => b - a)
71 -// let canvasHeight = 0
72 -// if (sortRes.length > 0) {
73 -// canvasHeight = sortRes[0]
74 -// }
75 -// if (config.height < canvasHeight || !config.height) {
76 -// return canvasHeight
77 -// }
78 -// return config.height
79 -// }
80 -
81 -/**
82 - * 将http转为https
83 - * @param {String}} rawUrl 图片资源url
84 - * @returns { string }
85 - */
86 -export function mapHttpToHttps(rawUrl) {
87 - if (rawUrl.indexOf(':') < 0 || rawUrl.startsWith('http://tmp')) {
88 - return rawUrl;
89 - }
90 - const urlComponent = rawUrl.split(':');
91 - if (urlComponent.length === 2) {
92 - if (urlComponent[0] === 'http') {
93 - urlComponent[0] = 'https';
94 - return `${urlComponent[0]}:${urlComponent[1]}`;
95 - }
96 - }
97 - return rawUrl;
98 -}
99 -
100 -/**
101 - * 获取 rpx => px 的转换系数
102 - * @returns { number } factor 单位转换系数 1rpx = factor * px
103 - */
104 -export const getFactor = () => {
105 - const sysInfo = Taro.getSystemInfoSync();
106 - const { screenWidth } = sysInfo;
107 - return screenWidth / 750;
108 -};
109 -
110 -/**
111 - * rpx => px 单位转换
112 - * @param { number } rpx - 需要转换的数值
113 - * @param { number } factor - 转化因子
114 - * @returns { number }
115 - */
116 -export const toPx = (rpx, factor = getFactor()) =>
117 - parseInt(String(rpx * factor), 10);
118 -
119 -/**
120 - * px => rpx 单位转换
121 - * @param { number } px - 需要转换的数值
122 - * @param { number } factor - 转化因子
123 - * @returns { number }
124 - */
125 -export const toRpx = (px, factor = getFactor()) =>
126 - parseInt(String(px / factor), 10);
127 -
128 -/**
129 - * 下载图片资源
130 - * @param { string } url
131 - * @returns { Promise }
132 - */
133 -export function downImage(url) {
134 - return new Promise<string>((resolve, reject) => {
135 - // eslint-disable-next-line no-undef
136 - if (/^http/.test(url) && !new RegExp(wx.env.USER_DATA_PATH).test(url)) {
137 - // wx.env.USER_DATA_PATH 文件系统中的用户目录路径
138 - Taro.downloadFile({
139 - url: mapHttpToHttps(url),
140 - success: (res) => {
141 - if (res.statusCode === 200) {
142 - resolve(res.tempFilePath);
143 - } else {
144 - console.log('下载失败', res);
145 - reject(res);
146 - }
147 - },
148 - fail(err) {
149 - console.log('下载失败了', err);
150 - reject(err);
151 - }
152 - });
153 - } else {
154 - resolve(url); // 支持本地地址
155 - }
156 - });
157 -}
158 -
159 -/**
160 - * 下载图片并获取图片信息
161 - * @param {} item 图片参数信息
162 - * @param {} index 图片下标
163 - * @returns { Promise } result 整理后的图片信息
164 - */
165 -export const getImageInfo = (item, index) =>
166 - new Promise((resolve, reject) => {
167 - const { x, y, width, height, url, zIndex } = item;
168 - downImage(url).then((imgPath) =>
169 - Taro.getImageInfo({ src: imgPath })
170 - .then((imgInfo) => {
171 - // 获取图片信息
172 - // 根据画布的宽高计算出图片绘制的大小,这里会保证图片绘制不变形, 即宽高比不变,截取再拉伸
173 - let sx; // 截图的起点 x 坐标
174 - let sy; // 截图的起点 y 坐标
175 - const borderRadius = item.borderRadius || 0;
176 - const imgWidth = toRpx(imgInfo.width); // 图片真实宽度 单位 px
177 - const imgHeight = toRpx(imgInfo.height); // 图片真实高度 单位 px
178 - // 根据宽高比截取图片
179 - if (imgWidth / imgHeight <= width / height) {
180 - sx = 0;
181 - sy = (imgHeight - (imgWidth / width) * height) / 2;
182 - } else {
183 - sy = 0;
184 - sx = (imgWidth - (imgHeight / height) * width) / 2;
185 - }
186 - // 给 canvas 画图准备参数,详见 ./draw.ts-drawImage
187 - const result = {
188 - type: 'image',
189 - borderRadius,
190 - borderWidth: item.borderWidth,
191 - borderColor: item.borderColor,
192 - borderRadiusGroup: item.borderRadiusGroup,
193 - zIndex: typeof zIndex !== 'undefined' ? zIndex : index,
194 - imgPath: url,
195 - sx,
196 - sy,
197 - sw: imgWidth - sx * 2,
198 - sh: imgHeight - sy * 2,
199 - x,
200 - y,
201 - w: width,
202 - h: height
203 - };
204 - resolve(result);
205 - })
206 - .catch((err) => {
207 - console.log('读取图片信息失败', err);
208 - reject(err);
209 - })
210 - );
211 - });
212 -
213 -/**
214 - * 获取线性渐变色
215 - * @param {CanvasContext} ctx canvas 实例对象
216 - * @param {String} color 线性渐变色,如 'linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #fff 100%)'
217 - * @param {Number} startX 起点 x 坐标
218 - * @param {Number} startY 起点 y 坐标
219 - * @param {Number} w 宽度
220 - * @param {Number} h 高度
221 - * @returns {}
222 - */
223 -// TODO: 待优化, 支持所有角度,多个颜色的线性渐变
224 -export function getLinearColor(
225 - ctx: CanvasContext,
226 - color,
227 - startX,
228 - startY,
229 - w,
230 - h
231 -) {
232 - if (
233 - typeof startX !== 'number' ||
234 - typeof startY !== 'number' ||
235 - typeof w !== 'number' ||
236 - typeof h !== 'number'
237 - ) {
238 - console.warn('坐标或者宽高只支持数字');
239 - return color;
240 - }
241 - let grd: CanvasGradient | string = color;
242 - if (color.includes('linear-gradient')) {
243 - // fillStyle 不支持线性渐变色
244 - const colorList = color.match(/\((\d+)deg,\s(.+)\s\d+%,\s(.+)\s\d+%/);
245 - const radian = colorList[1]; // 渐变弧度(角度)
246 - const color1 = colorList[2];
247 - const color2 = colorList[3];
248 -
249 - const L = Math.sqrt(w * w + h * h);
250 - const x = Math.ceil(Math.sin(180 - radian) * L);
251 - const y = Math.ceil(Math.cos(180 - radian) * L);
252 -
253 - // 根据弧度和宽高确定渐变色的两个点的坐标
254 - if (Number(radian) === 180 || Number(radian) === 0) {
255 - if (Number(radian) === 180) {
256 - grd = ctx.createLinearGradient(startX, startY, startX, startY + h);
257 - }
258 - if (Number(radian) === 0) {
259 - grd = ctx.createLinearGradient(startX, startY + h, startX, startY);
260 - }
261 - } else if (radian > 0 && radian < 180) {
262 - grd = ctx.createLinearGradient(startX, startY, x + startX, y + startY);
263 - } else {
264 - throw new Error('只支持0 <= 颜色弧度 <= 180');
265 - }
266 - (grd as CanvasGradient).addColorStop(0, color1);
267 - (grd as CanvasGradient).addColorStop(1, color2);
268 - }
269 - return grd;
270 -}
271 -
272 -/**
273 - * 根据文字对齐方式设置坐标
274 - * @param {*} imgPath
275 - * @param {*} index
276 - * @returns { Promise }
277 - */
278 -export function getTextX(textAlign, x, width) {
279 - let newX = x;
280 - if (textAlign === 'center') {
281 - newX = width / 2 + x;
282 - } else if (textAlign === 'right') {
283 - newX = width + x;
284 - }
285 - return newX;
286 -}
1 /* 1 /*
2 * @Date: 2022-09-19 14:11:06 2 * @Date: 2022-09-19 14:11:06
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2026-01-16 17:05:21 4 + * @LastEditTime: 2026-01-24 12:28:14
5 * @FilePath: /xyxBooking-weapp/src/utils/config.js 5 * @FilePath: /xyxBooking-weapp/src/utils/config.js
6 - * @Description: 文件描述 6 + * @Description: 服务器环境配置
7 */ 7 */
8 // TAG:服务器环境配置 8 // TAG:服务器环境配置
9 +// const isH5Dev = process.env.TARO_ENV === 'h5' && process.env.NODE_ENV === 'development';
10 +
9 const BASE_URL = process.env.NODE_ENV === 'production' 11 const BASE_URL = process.env.NODE_ENV === 'production'
10 - ? 'https://oa.onwall.cn' 12 + // ? 'https://oa.onwall.cn'
11 - // ? 'https://oa-dev.onwall.cn' 13 + ? 'https://oa-dev.onwall.cn'
14 + // ?'https://oa.jcedu.org'
12 : 'https://oa-dev.onwall.cn' 15 : 'https://oa-dev.onwall.cn'
13 - 16 + // : 'https://oa.jcedu.org'
17 +;
14 /** 18 /**
15 * 接口默认公共参数(避免在多个文件里硬编码) 19 * 接口默认公共参数(避免在多个文件里硬编码)
16 * - f:业务模块标识 20 * - f:业务模块标识
......
This diff is collapsed. Click to expand it.