diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json index aacf659..badb0a5 100644 --- a/.hbuilderx/launch.json +++ b/.hbuilderx/launch.json @@ -6,8 +6,8 @@ "type" : "uni-app:app-ios_simulator" }, { - "customPlaygroundType" : "device", - "playground" : "standard", + "customPlaygroundType" : "local", + "playground" : "custom", "type" : "uni-app:app-android" } ] diff --git a/components/sms-btn.uvue b/components/sms-btn.uvue index 714cae1..d222648 100644 --- a/components/sms-btn.uvue +++ b/components/sms-btn.uvue @@ -10,8 +10,9 @@ ref="popupRef" direction="center" :title="t('获取短信验证码')" + :size="500" > - + - + > + + + { + captcha.loading = false; + }, 200); } // 发送短信 diff --git a/manifest.json b/manifest.json index a997638..0216cf4 100644 --- a/manifest.json +++ b/manifest.json @@ -1,96 +1,96 @@ { - "name" : "cool-unix", - "appid" : "__UNI__651711F", - "description" : "完全开源、永久免费、上手容易、效率极高的开发脚手架", - "versionName" : "1.0.0", - "versionCode" : "100", - "uni-app-x" : {}, - /* 快应用特有相关 */ - "quickapp" : {}, - /* 小程序特有相关 */ - "mp-weixin" : { - "darkmode" : true, - "appid" : "wxdebc4de0b5584ca4", - "setting" : { - "urlCheck" : false, - "es6" : true - }, - "usingComponents" : true - }, - "mp-alipay" : { - "usingComponents" : true - }, - "mp-baidu" : { - "usingComponents" : true - }, - "mp-toutiao" : { - "usingComponents" : true - }, - "uniStatistics" : { - "enable" : false - }, - "vueVersion" : "3", - "app" : { - "distribute" : { - "icons" : { - "android" : { - "hdpi" : "", - "xhdpi" : "", - "xxhdpi" : "", - "xxxhdpi" : "" - } - } - } - }, - "web" : { - "darkmode" : true, - "router" : { - "mode" : "", - "base" : "./" - }, - "title" : "cool-unix" - }, - "app-harmony" : { - "distribute" : { - "bundleName" : "com.cool.unix", - "signingConfigs" : { - "default" : { - "certpath" : "/Users/icssoa/Library/Application Support/HBuilder X/extensions/launcher/agc-certs/1749115146522.cer", - "keyAlias" : "debugKey", - "keyPassword" : "0000001B0CD2170B509D76F6435F878B7ED2FE2E3EA6E7454E26523487B093238D4F7C8B7033D30DE80163", - "profile" : "/Users/icssoa/Library/Application Support/HBuilder X/extensions/launcher/agc-certs/1749115146522.p7b", - "signAlg" : "SHA256withECDSA", - "storeFile" : "/Users/icssoa/Library/Application Support/HBuilder X/extensions/launcher/agc-certs/1749115146522.p12", - "storePassword" : "0000001B0CD2170B509D76F6435F878B7ED2FE2E3EA6E7454E26523487B093238D4F7C8B7033D30DE80163" - } - }, - "icons" : { - "foreground" : "static/logo2.png", - "background" : "static/logo2.png" - } - } - }, - "app-android" : { - "distribute" : { - "modules" : {}, - "icons" : { - "hdpi" : "static/logo2.png", - "xhdpi" : "static/logo2.png", - "xxhdpi" : "static/logo2.png", - "xxxhdpi" : "static/logo2.png" - }, - "splashScreens" : { - "default" : {} - } - } - }, - "app-ios" : { - "distribute" : { - "modules" : {}, - "icons" : { - "appstore" : "static/logo2.png" - }, - "splashScreens" : {} - } - } -} + "name": "cool-unix", + "appid": "__UNI__651711F", + "description": "完全开源、永久免费、上手容易、效率极高的开发脚手架", + "versionName": "1.0.0", + "versionCode": "100", + "uni-app-x": {}, + /* 快应用特有相关 */ + "quickapp": {}, + /* 小程序特有相关 */ + "mp-weixin": { + "darkmode": true, + "appid": "wxdebc4de0b5584ca4", + "setting": { + "urlCheck": false, + "es6": true + }, + "usingComponents": true + }, + "mp-alipay": { + "usingComponents": true + }, + "mp-baidu": { + "usingComponents": true + }, + "mp-toutiao": { + "usingComponents": true + }, + "uniStatistics": { + "enable": false + }, + "vueVersion": "3", + "app": { + "distribute": { + "icons": { + "android": { + "hdpi": "", + "xhdpi": "", + "xxhdpi": "", + "xxxhdpi": "" + } + } + } + }, + "web": { + "darkmode": true, + "router": { + "mode": "", + "base": "./" + }, + "title": "cool-unix" + }, + "app-harmony": { + "distribute": { + "bundleName": "com.cool.unix", + "signingConfigs": { + "default": { + "certpath": "/Users/icssoa/Library/Application Support/HBuilder X/extensions/launcher/agc-certs/1749115146522.cer", + "keyAlias": "debugKey", + "keyPassword": "0000001B0CD2170B509D76F6435F878B7ED2FE2E3EA6E7454E26523487B093238D4F7C8B7033D30DE80163", + "profile": "/Users/icssoa/Library/Application Support/HBuilder X/extensions/launcher/agc-certs/1749115146522.p7b", + "signAlg": "SHA256withECDSA", + "storeFile": "/Users/icssoa/Library/Application Support/HBuilder X/extensions/launcher/agc-certs/1749115146522.p12", + "storePassword": "0000001B0CD2170B509D76F6435F878B7ED2FE2E3EA6E7454E26523487B093238D4F7C8B7033D30DE80163" + } + }, + "icons": { + "foreground": "static/logo2.png", + "background": "static/logo2.png" + } + } + }, + "app-android": { + "distribute": { + "modules": {}, + "icons": { + "hdpi": "static/logo2.png", + "xhdpi": "static/logo2.png", + "xxhdpi": "static/logo2.png", + "xxxhdpi": "static/logo2.png" + }, + "splashScreens": { + "default": {} + } + } + }, + "app-ios": { + "distribute": { + "modules": {}, + "icons": { + "appstore": "static/logo2.png" + }, + "splashScreens": {} + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index f89075a..8e45e10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cool-unix", - "version": "8.0.15", + "version": "8.0.16", "license": "MIT", "scripts": { "build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js", @@ -13,8 +13,8 @@ "devDependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.6", - "@cool-vue/ai": "^1.1.5", - "@cool-vue/vite-plugin": "^8.2.6", + "@cool-vue/ai": "^1.1.6", + "@cool-vue/vite-plugin": "^8.2.7", "@dcloudio/types": "^3.4.16", "@types/node": "^24.0.15", "@vue/compiler-sfc": "^3.5.16", diff --git a/pages.json b/pages.json index e668d03..dc06776 100644 --- a/pages.json +++ b/pages.json @@ -423,6 +423,12 @@ "style": { "navigationBarTitleText": "Canvas 画布" } + }, + { + "path": "other/svg", + "style": { + "navigationBarTitleText": "SVG 图标" + } } ] }, diff --git a/pages/demo/other/svg.uvue b/pages/demo/other/svg.uvue new file mode 100644 index 0000000..d11e5dd --- /dev/null +++ b/pages/demo/other/svg.uvue @@ -0,0 +1,69 @@ + + + diff --git a/pages/index/home.uvue b/pages/index/home.uvue index 0dd3cad..694f9c9 100644 --- a/pages/index/home.uvue +++ b/pages/index/home.uvue @@ -97,6 +97,13 @@ import Tabbar from "@/components/tabbar.uvue"; const ui = useUi(); const refs = useRefs(); +const svg = ` + + +`; + +const svg1 = "/static/svg/upload.svg"; + type Item = { label: string; icon?: string; @@ -426,6 +433,11 @@ const data = computed(() => { label: "Vibrate", icon: "volume-vibrate-line", path: "/pages/demo/other/vibrate" + }, + { + label: "SVG", + icon: "bubble-chart-line", + path: "/pages/demo/other/svg" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index acb9451..17f95f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,11 +22,11 @@ importers: specifier: ^7.27.6 version: 7.28.1 '@cool-vue/ai': - specifier: ^1.1.5 - version: 1.1.5 + specifier: ^1.1.6 + version: 1.1.6 '@cool-vue/vite-plugin': - specifier: ^8.2.6 - version: 8.2.6 + specifier: ^8.2.7 + version: 8.2.7 '@dcloudio/types': specifier: ^3.4.16 version: 3.4.16 @@ -81,12 +81,12 @@ packages: resolution: {integrity: sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==} engines: {node: '>=6.9.0'} - '@cool-vue/ai@1.1.5': - resolution: {integrity: sha512-H3A9uml1uiux+g9UPcZT119W3WepvxTx5hs38chwnaj3/zBEF0J2pDI0HNq5FShoHZLQ6+Rq+R7Se0X+CmNU5Q==} + '@cool-vue/ai@1.1.6': + resolution: {integrity: sha512-+5vEnjuMHhmOlAlozasGMaSkx2TZ5p45nOuLzx88ZVyqO0dMYXUJ5I8eVR5XV7huYCLCw7dYwfVg5B03ngsYwg==} hasBin: true - '@cool-vue/vite-plugin@8.2.6': - resolution: {integrity: sha512-Ey1qIMoHZOZdl/PxZ7qSa5A8hah0IlMVoyxPH7PQk6tAB1PNJiUfTkrPFi9vohFEeuj3WMZ5NhlRh+UIC3ZRXw==} + '@cool-vue/vite-plugin@8.2.7': + resolution: {integrity: sha512-Q3mKFvvVit7EYk+lmkUJnnUuDBlfsKL4i6oxyvAlbQDg1BQnANBI50V76ur6/BV9W8Onsk/GAo6a6yhFsThOqA==} '@dcloudio/types@3.4.16': resolution: {integrity: sha512-gJIr1OWtePTDDdjtp8Kh72S/ZGLunoSfHiUvRtXhBmAFNkDWuAKFO90hv62k3GYN/st04xUBQNtBfvhu/YHjww==} @@ -1358,7 +1358,7 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@cool-vue/ai@1.1.5': + '@cool-vue/ai@1.1.6': dependencies: axios: 1.10.0 chalk: 4.1.2 @@ -1370,7 +1370,7 @@ snapshots: transitivePeerDependencies: - debug - '@cool-vue/vite-plugin@8.2.6': + '@cool-vue/vite-plugin@8.2.7': dependencies: '@vue/compiler-sfc': 3.5.17 axios: 1.10.0 diff --git a/static/demo/svg/category.svg b/static/demo/svg/category.svg new file mode 100644 index 0000000..8859db5 --- /dev/null +++ b/static/demo/svg/category.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/demo/svg/points.svg b/static/demo/svg/points.svg new file mode 100644 index 0000000..7205ba7 --- /dev/null +++ b/static/demo/svg/points.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/demo/svg/shopping-cart.svg b/static/demo/svg/shopping-cart.svg new file mode 100644 index 0000000..2fba9fe --- /dev/null +++ b/static/demo/svg/shopping-cart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index e28d89a..340331f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,12 @@ "resolveJsonModule": true, "esModuleInterop": true, "noImplicitAny": false, - "types": ["@dcloudio/types", "vue", "./uni_modules/cool-ui/index.d.ts"], + "types": [ + "@dcloudio/types", + "vue", + "./uni_modules/cool-ui/index.d.ts", + "./uni_modules/cool-svg/index.d.ts" + ], "lib": ["esnext", "dom"], "outDir": "esbuild", "paths": { diff --git a/types/uni-app.d.ts b/types/uni-app.d.ts index 3d24c3f..bbd74d5 100644 --- a/types/uni-app.d.ts +++ b/types/uni-app.d.ts @@ -456,3 +456,19 @@ declare interface CanvasContext extends HTMLCanvasElement { declare type Image = HTMLImageElement; declare type VueApp = any; + +declare interface UniNativeViewElement extends UniElement { + bindAndroidView(view: any): void; + bindIOSView(): void; + bindHarmonyFrameNode(node: FrameNode): void; + bindHarmonyWrappedBuilder( + builder: WrappedBuilder<[options: O]> + ): BuilderNode<[O]>; + getHarmonyFrameNode(): FrameNode | null; +} + +declare type UniNativeViewInitEvent = { + detail: { + element: UniNativeViewElement; + }; +}; diff --git a/uni_modules/cool-svg/components/cl-svg/cl-svg.uvue b/uni_modules/cool-svg/components/cl-svg/cl-svg.uvue new file mode 100644 index 0000000..0298d0e --- /dev/null +++ b/uni_modules/cool-svg/components/cl-svg/cl-svg.uvue @@ -0,0 +1,231 @@ + + + diff --git a/uni_modules/cool-svg/index.d.ts b/uni_modules/cool-svg/index.d.ts new file mode 100644 index 0000000..0e9b0d6 --- /dev/null +++ b/uni_modules/cool-svg/index.d.ts @@ -0,0 +1,7 @@ +export {}; + +declare module "vue" { + export interface GlobalComponents { + "cl-svg": (typeof import("./components/cl-svg/cl-svg.uvue"))["default"]; + } +} diff --git a/uni_modules/cool-svg/package.json b/uni_modules/cool-svg/package.json new file mode 100644 index 0000000..efa7f0c --- /dev/null +++ b/uni_modules/cool-svg/package.json @@ -0,0 +1,82 @@ +{ + "id": "cool-svg", + "displayName": "cool-svg", + "version": "1.0.0", + "description": "cool-svg", + "keywords": [ + "cool-svg" + ], + "repository": "", + "engines": { + "HBuilderX": "^4.75" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "", + "data": "", + "permissions": "" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "u", + "aliyun": "u", + "alipay": "u" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-android": "u", + "app-ios": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} diff --git a/uni_modules/cool-svg/utssdk/app-android/config.json b/uni_modules/cool-svg/utssdk/app-android/config.json new file mode 100644 index 0000000..d1ccc13 --- /dev/null +++ b/uni_modules/cool-svg/utssdk/app-android/config.json @@ -0,0 +1,4 @@ +{ + "minSdkVersion": "21", + "dependencies": ["com.caverock:androidsvg:1.4"] +} diff --git a/uni_modules/cool-svg/utssdk/app-android/index.uts b/uni_modules/cool-svg/utssdk/app-android/index.uts new file mode 100644 index 0000000..02184c9 --- /dev/null +++ b/uni_modules/cool-svg/utssdk/app-android/index.uts @@ -0,0 +1,132 @@ +import PictureDrawable from "android.graphics.drawable.PictureDrawable"; +import ImageView from "android.widget.ImageView"; +import File from "java.io.File"; +import FileInputStream from "java.io.FileInputStream"; +import Color from "android.graphics.Color"; +import RenderOptions from "com.caverock.androidsvg.RenderOptions"; +import Base64 from "android.util.Base64"; +import Charset from "java.nio.charset.Charset"; +import StandardCharsets from "java.nio.charset.StandardCharsets"; + +/** + * CoolSvg Android 平台 SVG 渲染器 + * 支持多种 SVG 数据格式: + * - base64 编码的数据 URL + * - URL 编码的数据 URL + * - 本地文件路径 + * - Android 资源文件 + */ +export class CoolSvg { + /** 原生视图元素 */ + $element: UniNativeViewElement; + /** Android ImageView 实例 */ + imageView: ImageView | null = null; + + /** + * 构造函数 + * @param element uni-app x 原生视图元素 + */ + constructor(element: UniNativeViewElement) { + this.$element = element; + this.imageView = new ImageView(UTSAndroid.getAppContext()!); + this.$element.bindAndroidView(this.imageView!); + } + + /** + * 加载并渲染 SVG + * @param src SVG 数据源,支持以下格式: + * - data:image/svg+xml;base64, + * - data:image/svg+xml, + * - 本地文件路径 + * @param color 填充颜色,用于替换 SVG 中 path 元素的 fill 属性 + */ + load(src: string, color: string) { + // 空字符串检查 + if (src == "") { + return; + } + + try { + if (src.startsWith("data:image/svg")) { + // 处理数据 URL 格式的 SVG + this.loadFromDataUrl(src, color); + } else { + // 处理本地文件或资源文件 + this.loadFromFile(src, color); + } + } catch (e) { + // 打印异常信息用于调试 + e.printStackTrace(); + } + } + + /** + * 从数据 URL 加载 SVG + * @param dataUrl 数据 URL 字符串 + * @param color 填充颜色 + */ + private loadFromDataUrl(dataUrl: string, color: string) { + let svgString: string; + + if (dataUrl.startsWith("data:image/svg+xml;base64,")) { + // 处理 base64 编码的 SVG + const base64Prefix = "data:image/svg+xml;base64,"; + const base64Data = dataUrl.substring(base64Prefix.length); + const decodedBytes = Base64.decode(base64Data, Base64.DEFAULT); + svgString = String(decodedBytes, StandardCharsets.UTF_8); + } else { + // 处理 URL 编码的 SVG + const urlPrefix = "data:image/svg+xml,"; + const encodedSvg = dataUrl.substring(urlPrefix.length); + svgString = decodeURIComponent(encodedSvg) ?? ''; + } + + const svg = com.caverock.androidsvg.SVG.getFromString(svgString); + this.render(svg, color); + } + + /** + * 从文件加载 SVG + * @param src 文件路径 + * @param color 填充颜色 + */ + private loadFromFile(src: string, color: string) { + // uni-app x 正式打包会将资源文件放在 Android asset 中 + const path = UTSAndroid.getResourcePath(src); + + if (path.startsWith("/android_asset")) { + // 从 Android 资源文件中加载 + const assetPath = path.substring(15); // 移除 "/android_asset" 前缀 + const svg = com.caverock.androidsvg.SVG.getFromAsset( + UTSAndroid.getAppContext()!.getAssets(), + assetPath + ); + this.render(svg, color); + } else { + // 从本地文件系统加载 + const file = new File(path); + if (file.exists()) { + const svg = com.caverock.androidsvg.SVG.getFromInputStream( + new FileInputStream(file) + ); + this.render(svg, color); + } + } + } + + /** + * 渲染 SVG 到 ImageView + * @param svg AndroidSVG 对象 + * @param color 填充颜色,应用到所有 path 元素 + */ + private render(svg: com.caverock.androidsvg.SVG, color: string) { + // 创建渲染选项,设置 CSS 样式来改变 SVG 的填充颜色 + const options = RenderOptions.create().css(`path { fill: ${color}; }`); + + // 将 SVG 渲染为 Picture,然后转换为 Drawable + const drawable = new PictureDrawable(svg.renderToPicture(options)); + + // 设置到 ImageView 中显示 + this.imageView?.setImageDrawable(drawable); + } +}