Browse Source

单图徽章代码提交

lzm_web
Linzm 8 months ago
parent
commit
ea8b23586a
  1. 2
      index.html
  2. 450
      package-lock.json
  3. 2
      package.json
  4. 140
      pnpm-lock.yaml
  5. 75
      src/api/badge.ts
  6. 2
      src/config/config.ts
  7. 2
      src/lang/data/en.ts
  8. 2
      src/lang/data/ko.ts
  9. 2
      src/lang/data/zh-CN.ts
  10. 2
      src/lang/data/zh-TW.ts
  11. 42
      src/router/index.ts
  12. 329
      src/views/badge/cropper.vue
  13. 153
      src/views/badge/index.vue
  14. 45
      src/views/badge/myOrder.vue
  15. 20
      src/views/badge/orderDetail.vue
  16. 295
      src/views/badge/preview.vue
  17. 108
      src/views/badge/record.vue
  18. 29
      src/views/login/helpers/transfer.ts
  19. 131
      src/views/login/index.vue

2
index.html

@ -6,7 +6,7 @@
<meta name="description" content="The template for Vue3 Vant Mobile" /> <meta name="description" content="The template for Vue3 Vant Mobile" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover, user-scalable=no"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover, user-scalable=no"/>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<title>3D</title> <title>葡哇立体肖像</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

450
package-lock.json generated

@ -47,6 +47,7 @@
"vite": "^5.3.3", "vite": "^5.3.3",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
"vue-cropperjs": "^5.0.0",
"vue-i18n": "^9.9.0", "vue-i18n": "^9.9.0",
"vue-router": "^4.2.2", "vue-router": "^4.2.2",
"vue-router-better-scroller": "^0.0.0", "vue-router-better-scroller": "^0.0.0",
@ -96,6 +97,7 @@
"typescript": "^4.9.5", "typescript": "^4.9.5",
"unplugin-auto-import": "^0.12.2", "unplugin-auto-import": "^0.12.2",
"unplugin-vue-components": "^0.22.12", "unplugin-vue-components": "^0.22.12",
"unplugin-vue-define-options": "^3.0.0-beta.14",
"vite": "^4.3.9", "vite": "^4.3.9",
"vite-plugin-mkcert": "^1.17.5", "vite-plugin-mkcert": "^1.17.5",
"vite-plugin-vconsole": "^1.3.1", "vite-plugin-vconsole": "^1.3.1",
@ -526,11 +528,11 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.27.2", "version": "7.27.5",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.5.tgz",
"integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==",
"dependencies": { "dependencies": {
"@babel/types": "^7.27.1" "@babel/types": "^7.27.3"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@ -1697,9 +1699,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.27.1", "version": "7.27.3",
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.1.tgz", "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.3.tgz",
"integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.27.1", "@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1" "@babel/helper-validator-identifier": "^7.27.1"
@ -3695,6 +3697,73 @@
"path-browserify": "^1.0.1" "path-browserify": "^1.0.1"
} }
}, },
"node_modules/@vue-macros/common": {
"version": "3.0.0-beta.14",
"resolved": "https://registry.npmmirror.com/@vue-macros/common/-/common-3.0.0-beta.14.tgz",
"integrity": "sha512-Eto2MnuaLAdC/rIyPPt7wnFU4l1u5TUw42yRB9aSc3dwMbLV5aka5gdyyt3OMKs4rgyPx8nssEN8sc0kz4PltA==",
"dev": true,
"dependencies": {
"@vue/compiler-sfc": "^3.5.16",
"ast-kit": "^2.1.0",
"local-pkg": "^1.1.1",
"magic-string-ast": "^0.9.1",
"unplugin-utils": "^0.2.4"
},
"engines": {
"node": ">=20.18.0"
},
"funding": {
"url": "https://github.com/sponsors/vue-macros"
},
"peerDependencies": {
"vue": "^2.7.0 || ^3.2.25"
},
"peerDependenciesMeta": {
"vue": {
"optional": true
}
}
},
"node_modules/@vue-macros/common/node_modules/confbox": {
"version": "0.2.2",
"resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz",
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
"dev": true
},
"node_modules/@vue-macros/common/node_modules/local-pkg": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.1.tgz",
"integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==",
"dev": true,
"dependencies": {
"mlly": "^1.7.4",
"pkg-types": "^2.0.1",
"quansync": "^0.2.8"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vue-macros/common/node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
"node_modules/@vue-macros/common/node_modules/pkg-types": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.1.0.tgz",
"integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
"dev": true,
"dependencies": {
"confbox": "^0.2.1",
"exsolve": "^1.0.1",
"pathe": "^2.0.3"
}
},
"node_modules/@vue/babel-helper-vue-transform-on": { "node_modules/@vue/babel-helper-vue-transform-on": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz",
@ -4286,6 +4355,44 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/ast-kit": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/ast-kit/-/ast-kit-2.1.0.tgz",
"integrity": "sha512-ROM2LlXbZBZVk97crfw8PGDOBzzsJvN2uJCmwswvPUNyfH14eg90mSN3xNqsri1JS1G9cz0VzeDUhxJkTrr4Ew==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.27.3",
"pathe": "^2.0.3"
},
"engines": {
"node": ">=20.18.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/ast-kit/node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
"node_modules/ast-walker-scope": {
"version": "0.8.1",
"resolved": "https://registry.npmmirror.com/ast-walker-scope/-/ast-walker-scope-0.8.1.tgz",
"integrity": "sha512-72XOdbzQCMKERvFrxAykatn2pu7osPNq/sNUzwcHdWzwPvOsNpPqkawfDXVvQbA2RT+ivtsMNjYdojTUZitt1A==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.27.2",
"ast-kit": "^2.0.0"
},
"engines": {
"node": ">=20.18.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/async-function": { "node_modules/async-function": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz",
@ -5229,6 +5336,11 @@
} }
} }
}, },
"node_modules/cropperjs": {
"version": "1.6.2",
"resolved": "https://registry.npmmirror.com/cropperjs/-/cropperjs-1.6.2.tgz",
"integrity": "sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA=="
},
"node_modules/cross-env": { "node_modules/cross-env": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz", "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz",
@ -6918,6 +7030,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/exsolve": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/exsolve/-/exsolve-1.0.5.tgz",
"integrity": "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==",
"dev": true
},
"node_modules/extend": { "node_modules/extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz",
@ -9725,6 +9843,30 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/magic-string-ast": {
"version": "0.9.1",
"resolved": "https://registry.npmmirror.com/magic-string-ast/-/magic-string-ast-0.9.1.tgz",
"integrity": "sha512-18dv2ZlSSgJ/jDWlZGKfnDJx56ilNlYq9F7NnwuWTErsmYmqJ2TWE4l1o2zlUHBYUGBy3tIhPCC1gxq8M5HkMA==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.17"
},
"engines": {
"node": ">=20.18.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/magic-string-ast/node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/make-dir": { "node_modules/make-dir": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz", "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz",
@ -11619,6 +11761,22 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/quansync": {
"version": "0.2.10",
"resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz",
"integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/antfu"
},
{
"type": "individual",
"url": "https://github.com/sponsors/sxzz"
}
]
},
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -13693,6 +13851,40 @@
} }
} }
}, },
"node_modules/unplugin-utils": {
"version": "0.2.4",
"resolved": "https://registry.npmmirror.com/unplugin-utils/-/unplugin-utils-0.2.4.tgz",
"integrity": "sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==",
"dev": true,
"dependencies": {
"pathe": "^2.0.2",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=18.12.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/unplugin-utils/node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
"node_modules/unplugin-utils/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/unplugin-vue-components": { "node_modules/unplugin-vue-components": {
"version": "0.22.12", "version": "0.22.12",
"resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.22.12.tgz", "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.22.12.tgz",
@ -13747,6 +13939,49 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/unplugin-vue-define-options": {
"version": "3.0.0-beta.14",
"resolved": "https://registry.npmmirror.com/unplugin-vue-define-options/-/unplugin-vue-define-options-3.0.0-beta.14.tgz",
"integrity": "sha512-sbcFwF4ZkeQSUqw5Qw8o6Uf5Tc3P9umQf5bddQ8Kts9DEyZdTX+WlqjvyZzGSBPdFlYKm2CBj+xtNf+cOpSTnA==",
"dev": true,
"dependencies": {
"@vue-macros/common": "3.0.0-beta.14",
"ast-walker-scope": "^0.8.1",
"unplugin": "^2.3.5"
},
"engines": {
"node": ">=20.18.0"
},
"funding": {
"url": "https://github.com/sponsors/vue-macros"
}
},
"node_modules/unplugin-vue-define-options/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/unplugin-vue-define-options/node_modules/unplugin": {
"version": "2.3.5",
"resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-2.3.5.tgz",
"integrity": "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==",
"dev": true,
"dependencies": {
"acorn": "^8.14.1",
"picomatch": "^4.0.2",
"webpack-virtual-modules": "^0.6.2"
},
"engines": {
"node": ">=18.12.0"
}
},
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
@ -14014,6 +14249,17 @@
"clipboard": "^2.0.6" "clipboard": "^2.0.6"
} }
}, },
"node_modules/vue-cropperjs": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/vue-cropperjs/-/vue-cropperjs-5.0.0.tgz",
"integrity": "sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==",
"dependencies": {
"cropperjs": "^1.5.6"
},
"peerDependencies": {
"vue": ">=3.0.0"
}
},
"node_modules/vue-demi": { "node_modules/vue-demi": {
"version": "0.14.10", "version": "0.14.10",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz",
@ -14898,11 +15144,11 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.27.2", "version": "7.27.5",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.5.tgz",
"integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==",
"requires": { "requires": {
"@babel/types": "^7.27.1" "@babel/types": "^7.27.3"
} }
}, },
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": { "@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
@ -15658,9 +15904,9 @@
} }
}, },
"@babel/types": { "@babel/types": {
"version": "7.27.1", "version": "7.27.3",
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.1.tgz", "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.3.tgz",
"integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==",
"requires": { "requires": {
"@babel/helper-string-parser": "^7.27.1", "@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1" "@babel/helper-validator-identifier": "^7.27.1"
@ -16907,6 +17153,55 @@
"path-browserify": "^1.0.1" "path-browserify": "^1.0.1"
} }
}, },
"@vue-macros/common": {
"version": "3.0.0-beta.14",
"resolved": "https://registry.npmmirror.com/@vue-macros/common/-/common-3.0.0-beta.14.tgz",
"integrity": "sha512-Eto2MnuaLAdC/rIyPPt7wnFU4l1u5TUw42yRB9aSc3dwMbLV5aka5gdyyt3OMKs4rgyPx8nssEN8sc0kz4PltA==",
"dev": true,
"requires": {
"@vue/compiler-sfc": "^3.5.16",
"ast-kit": "^2.1.0",
"local-pkg": "^1.1.1",
"magic-string-ast": "^0.9.1",
"unplugin-utils": "^0.2.4"
},
"dependencies": {
"confbox": {
"version": "0.2.2",
"resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz",
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
"dev": true
},
"local-pkg": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.1.tgz",
"integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==",
"dev": true,
"requires": {
"mlly": "^1.7.4",
"pkg-types": "^2.0.1",
"quansync": "^0.2.8"
}
},
"pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
"pkg-types": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.1.0.tgz",
"integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
"dev": true,
"requires": {
"confbox": "^0.2.1",
"exsolve": "^1.0.1",
"pathe": "^2.0.3"
}
}
}
},
"@vue/babel-helper-vue-transform-on": { "@vue/babel-helper-vue-transform-on": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz", "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz",
@ -17371,6 +17666,34 @@
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true "dev": true
}, },
"ast-kit": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/ast-kit/-/ast-kit-2.1.0.tgz",
"integrity": "sha512-ROM2LlXbZBZVk97crfw8PGDOBzzsJvN2uJCmwswvPUNyfH14eg90mSN3xNqsri1JS1G9cz0VzeDUhxJkTrr4Ew==",
"dev": true,
"requires": {
"@babel/parser": "^7.27.3",
"pathe": "^2.0.3"
},
"dependencies": {
"pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
}
}
},
"ast-walker-scope": {
"version": "0.8.1",
"resolved": "https://registry.npmmirror.com/ast-walker-scope/-/ast-walker-scope-0.8.1.tgz",
"integrity": "sha512-72XOdbzQCMKERvFrxAykatn2pu7osPNq/sNUzwcHdWzwPvOsNpPqkawfDXVvQbA2RT+ivtsMNjYdojTUZitt1A==",
"dev": true,
"requires": {
"@babel/parser": "^7.27.2",
"ast-kit": "^2.0.0"
}
},
"async-function": { "async-function": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz",
@ -18027,6 +18350,11 @@
"parse-json": "^5.2.0" "parse-json": "^5.2.0"
} }
}, },
"cropperjs": {
"version": "1.6.2",
"resolved": "https://registry.npmmirror.com/cropperjs/-/cropperjs-1.6.2.tgz",
"integrity": "sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA=="
},
"cross-env": { "cross-env": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz", "resolved": "https://registry.npmmirror.com/cross-env/-/cross-env-7.0.3.tgz",
@ -19264,6 +19592,12 @@
"homedir-polyfill": "^1.0.1" "homedir-polyfill": "^1.0.1"
} }
}, },
"exsolve": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/exsolve/-/exsolve-1.0.5.tgz",
"integrity": "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==",
"dev": true
},
"extend": { "extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz",
@ -21322,6 +21656,26 @@
"@jridgewell/sourcemap-codec": "^1.4.13" "@jridgewell/sourcemap-codec": "^1.4.13"
} }
}, },
"magic-string-ast": {
"version": "0.9.1",
"resolved": "https://registry.npmmirror.com/magic-string-ast/-/magic-string-ast-0.9.1.tgz",
"integrity": "sha512-18dv2ZlSSgJ/jDWlZGKfnDJx56ilNlYq9F7NnwuWTErsmYmqJ2TWE4l1o2zlUHBYUGBy3tIhPCC1gxq8M5HkMA==",
"dev": true,
"requires": {
"magic-string": "^0.30.17"
},
"dependencies": {
"magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
"requires": {
"@jridgewell/sourcemap-codec": "^1.5.0"
}
}
}
},
"make-dir": { "make-dir": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz", "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz",
@ -22656,6 +23010,12 @@
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true "dev": true
}, },
"quansync": {
"version": "0.2.10",
"resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz",
"integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==",
"dev": true
},
"queue-microtask": { "queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -24140,6 +24500,30 @@
"unplugin": "^1.0.1" "unplugin": "^1.0.1"
} }
}, },
"unplugin-utils": {
"version": "0.2.4",
"resolved": "https://registry.npmmirror.com/unplugin-utils/-/unplugin-utils-0.2.4.tgz",
"integrity": "sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==",
"dev": true,
"requires": {
"pathe": "^2.0.2",
"picomatch": "^4.0.2"
},
"dependencies": {
"pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
"picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true
}
}
},
"unplugin-vue-components": { "unplugin-vue-components": {
"version": "0.22.12", "version": "0.22.12",
"resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.22.12.tgz", "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.22.12.tgz",
@ -24178,6 +24562,36 @@
} }
} }
}, },
"unplugin-vue-define-options": {
"version": "3.0.0-beta.14",
"resolved": "https://registry.npmmirror.com/unplugin-vue-define-options/-/unplugin-vue-define-options-3.0.0-beta.14.tgz",
"integrity": "sha512-sbcFwF4ZkeQSUqw5Qw8o6Uf5Tc3P9umQf5bddQ8Kts9DEyZdTX+WlqjvyZzGSBPdFlYKm2CBj+xtNf+cOpSTnA==",
"dev": true,
"requires": {
"@vue-macros/common": "3.0.0-beta.14",
"ast-walker-scope": "^0.8.1",
"unplugin": "^2.3.5"
},
"dependencies": {
"picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true
},
"unplugin": {
"version": "2.3.5",
"resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-2.3.5.tgz",
"integrity": "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==",
"dev": true,
"requires": {
"acorn": "^8.14.1",
"picomatch": "^4.0.2",
"webpack-virtual-modules": "^0.6.2"
}
}
}
},
"update-browserslist-db": { "update-browserslist-db": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
@ -24383,6 +24797,14 @@
"clipboard": "^2.0.6" "clipboard": "^2.0.6"
} }
}, },
"vue-cropperjs": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/vue-cropperjs/-/vue-cropperjs-5.0.0.tgz",
"integrity": "sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==",
"requires": {
"cropperjs": "^1.5.6"
}
},
"vue-demi": { "vue-demi": {
"version": "0.14.10", "version": "0.14.10",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz",

2
package.json

@ -60,6 +60,7 @@
"vite": "^5.3.3", "vite": "^5.3.3",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
"vue-cropper-h5": "^2.0.1",
"vue-cropperjs": "^5.0.0", "vue-cropperjs": "^5.0.0",
"vue-i18n": "^9.9.0", "vue-i18n": "^9.9.0",
"vue-router": "^4.2.2", "vue-router": "^4.2.2",
@ -110,6 +111,7 @@
"typescript": "^4.9.5", "typescript": "^4.9.5",
"unplugin-auto-import": "^0.12.2", "unplugin-auto-import": "^0.12.2",
"unplugin-vue-components": "^0.22.12", "unplugin-vue-components": "^0.22.12",
"unplugin-vue-define-options": "^3.0.0-beta.14",
"vite": "^4.3.9", "vite": "^4.3.9",
"vite-plugin-mkcert": "^1.17.5", "vite-plugin-mkcert": "^1.17.5",
"vite-plugin-vconsole": "^1.3.1", "vite-plugin-vconsole": "^1.3.1",

140
pnpm-lock.yaml

@ -122,6 +122,9 @@ importers:
vue-clipboard3: vue-clipboard3:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.0.0 version: 2.0.0
vue-cropper-h5:
specifier: ^2.0.1
version: 2.0.1(typescript@4.9.5)
vue-cropperjs: vue-cropperjs:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.0.0(vue@3.5.13(typescript@4.9.5)) version: 5.0.0(vue@3.5.13(typescript@4.9.5))
@ -261,6 +264,9 @@ importers:
unplugin-vue-components: unplugin-vue-components:
specifier: ^0.22.12 specifier: ^0.22.12
version: 0.22.12(@babel/parser@7.27.5)(rollup@3.29.5)(vue@3.5.13(typescript@4.9.5)) version: 0.22.12(@babel/parser@7.27.5)(rollup@3.29.5)(vue@3.5.13(typescript@4.9.5))
unplugin-vue-define-options:
specifier: ^3.0.0-beta.14
version: 3.0.0-beta.14(vue@3.5.13(typescript@4.9.5))
vite-plugin-mkcert: vite-plugin-mkcert:
specifier: ^1.17.5 specifier: ^1.17.5
version: 1.17.6(vite@5.4.14(@types/node@18.19.76)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)) version: 1.17.6(vite@5.4.14(@types/node@18.19.76)(less@4.2.2)(sass@1.85.0)(terser@5.39.0))
@ -1792,6 +1798,15 @@ packages:
'@volar/typescript@1.11.1': '@volar/typescript@1.11.1':
resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==}
'@vue-macros/common@3.0.0-beta.14':
resolution: {integrity: sha512-Eto2MnuaLAdC/rIyPPt7wnFU4l1u5TUw42yRB9aSc3dwMbLV5aka5gdyyt3OMKs4rgyPx8nssEN8sc0kz4PltA==}
engines: {node: '>=20.18.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
peerDependenciesMeta:
vue:
optional: true
'@vue/babel-helper-vue-transform-on@1.2.5': '@vue/babel-helper-vue-transform-on@1.2.5':
resolution: {integrity: sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==} resolution: {integrity: sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==}
@ -1918,6 +1933,11 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
acorn@8.14.1:
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
engines: {node: '>=0.4.0'}
hasBin: true
aggregate-error@3.1.0: aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -2013,6 +2033,14 @@ packages:
assertion-error@1.1.0: assertion-error@1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
ast-kit@2.1.0:
resolution: {integrity: sha512-ROM2LlXbZBZVk97crfw8PGDOBzzsJvN2uJCmwswvPUNyfH14eg90mSN3xNqsri1JS1G9cz0VzeDUhxJkTrr4Ew==}
engines: {node: '>=20.18.0'}
ast-walker-scope@0.8.1:
resolution: {integrity: sha512-72XOdbzQCMKERvFrxAykatn2pu7osPNq/sNUzwcHdWzwPvOsNpPqkawfDXVvQbA2RT+ivtsMNjYdojTUZitt1A==}
engines: {node: '>=20.18.0'}
async-function@1.0.0: async-function@1.0.0:
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -2292,6 +2320,9 @@ packages:
confbox@0.1.8: confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
confbox@0.2.2:
resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
consola@2.15.3: consola@2.15.3:
resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==}
@ -2762,6 +2793,9 @@ packages:
resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
exsolve@1.0.5:
resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==}
extend@3.0.2: extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
@ -3516,6 +3550,10 @@ packages:
resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
engines: {node: '>=14'} engines: {node: '>=14'}
local-pkg@1.1.1:
resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==}
engines: {node: '>=14'}
locate-path@2.0.0: locate-path@2.0.0:
resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -3604,6 +3642,10 @@ packages:
lru-cache@5.1.1: lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
magic-string-ast@0.9.1:
resolution: {integrity: sha512-18dv2ZlSSgJ/jDWlZGKfnDJx56ilNlYq9F7NnwuWTErsmYmqJ2TWE4l1o2zlUHBYUGBy3tIhPCC1gxq8M5HkMA==}
engines: {node: '>=20.18.0'}
magic-string@0.27.0: magic-string@0.27.0:
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -4071,6 +4113,9 @@ packages:
pkg-types@1.3.1: pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
pkg-types@2.1.0:
resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==}
pkg-up@3.1.0: pkg-up@3.1.0:
resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -4175,6 +4220,9 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'} engines: {node: '>=6'}
quansync@0.2.10:
resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
queue-microtask@1.2.3: queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -4784,6 +4832,10 @@ packages:
'@vueuse/core': '@vueuse/core':
optional: true optional: true
unplugin-utils@0.2.4:
resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==}
engines: {node: '>=18.12.0'}
unplugin-vue-components@0.22.12: unplugin-vue-components@0.22.12:
resolution: {integrity: sha512-FxyzsuBvMCYPIk+8cgscGBQ345tvwVu+qY5IhE++eorkyvA4Z1TiD/HCiim+Kbqozl10i4K+z+NCa2WO2jexRA==} resolution: {integrity: sha512-FxyzsuBvMCYPIk+8cgscGBQ345tvwVu+qY5IhE++eorkyvA4Z1TiD/HCiim+Kbqozl10i4K+z+NCa2WO2jexRA==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -4794,10 +4846,18 @@ packages:
'@babel/parser': '@babel/parser':
optional: true optional: true
unplugin-vue-define-options@3.0.0-beta.14:
resolution: {integrity: sha512-sbcFwF4ZkeQSUqw5Qw8o6Uf5Tc3P9umQf5bddQ8Kts9DEyZdTX+WlqjvyZzGSBPdFlYKm2CBj+xtNf+cOpSTnA==}
engines: {node: '>=20.18.0'}
unplugin@1.16.1: unplugin@1.16.1:
resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
unplugin@2.3.5:
resolution: {integrity: sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==}
engines: {node: '>=18.12.0'}
update-browserslist-db@1.1.2: update-browserslist-db@1.1.2:
resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
hasBin: true hasBin: true
@ -4924,6 +4984,12 @@ packages:
vue-clipboard3@2.0.0: vue-clipboard3@2.0.0:
resolution: {integrity: sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A==} resolution: {integrity: sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A==}
vue-cropper-h5@2.0.1:
resolution: {integrity: sha512-3d6MP1zUGiZGxwrUo3ShZ8JYdyF7JUUryJBHaz/zC/3ZYXqnU8srvTGEjN0w7qhZwTkpArvpd0f3OkhXsaEtdw==}
vue-cropper@1.1.4:
resolution: {integrity: sha512-5m98vBsCEI9rbS4JxELxXidtAui3qNyTHLHg67Qbn7g8cg+E6LcnC+hh3SM/p94x6mFh6KRxT1ttnta+wCYqWA==}
vue-cropperjs@5.0.0: vue-cropperjs@5.0.0:
resolution: {integrity: sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==} resolution: {integrity: sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==}
peerDependencies: peerDependencies:
@ -6707,6 +6773,16 @@ snapshots:
'@volar/language-core': 1.11.1 '@volar/language-core': 1.11.1
path-browserify: 1.0.1 path-browserify: 1.0.1
'@vue-macros/common@3.0.0-beta.14(vue@3.5.13(typescript@4.9.5))':
dependencies:
'@vue/compiler-sfc': 3.5.16
ast-kit: 2.1.0
local-pkg: 1.1.1
magic-string-ast: 0.9.1
unplugin-utils: 0.2.4
optionalDependencies:
vue: 3.5.13(typescript@4.9.5)
'@vue/babel-helper-vue-transform-on@1.2.5': {} '@vue/babel-helper-vue-transform-on@1.2.5': {}
'@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.9)': '@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.9)':
@ -6739,7 +6815,7 @@ snapshots:
'@vue/compiler-core@3.5.13': '@vue/compiler-core@3.5.13':
dependencies: dependencies:
'@babel/parser': 7.26.9 '@babel/parser': 7.27.5
'@vue/shared': 3.5.13 '@vue/shared': 3.5.13
entities: 4.5.0 entities: 4.5.0
estree-walker: 2.0.2 estree-walker: 2.0.2
@ -6908,6 +6984,8 @@ snapshots:
acorn@8.14.0: {} acorn@8.14.0: {}
acorn@8.14.1: {}
aggregate-error@3.1.0: aggregate-error@3.1.0:
dependencies: dependencies:
clean-stack: 2.2.0 clean-stack: 2.2.0
@ -7018,6 +7096,16 @@ snapshots:
assertion-error@1.1.0: {} assertion-error@1.1.0: {}
ast-kit@2.1.0:
dependencies:
'@babel/parser': 7.27.5
pathe: 2.0.3
ast-walker-scope@0.8.1:
dependencies:
'@babel/parser': 7.27.5
ast-kit: 2.1.0
async-function@1.0.0: {} async-function@1.0.0: {}
async-validator@4.2.5: {} async-validator@4.2.5: {}
@ -7352,6 +7440,8 @@ snapshots:
confbox@0.1.8: {} confbox@0.1.8: {}
confbox@0.2.2: {}
consola@2.15.3: {} consola@2.15.3: {}
constant-case@3.0.4: constant-case@3.0.4:
@ -8007,6 +8097,8 @@ snapshots:
dependencies: dependencies:
homedir-polyfill: 1.0.3 homedir-polyfill: 1.0.3
exsolve@1.0.5: {}
extend@3.0.2: {} extend@3.0.2: {}
external-editor@2.2.0: external-editor@2.2.0:
@ -8840,6 +8932,12 @@ snapshots:
local-pkg@0.4.3: {} local-pkg@0.4.3: {}
local-pkg@1.1.1:
dependencies:
mlly: 1.7.4
pkg-types: 2.1.0
quansync: 0.2.10
locate-path@2.0.0: locate-path@2.0.0:
dependencies: dependencies:
p-locate: 2.0.0 p-locate: 2.0.0
@ -8919,6 +9017,10 @@ snapshots:
dependencies: dependencies:
yallist: 3.1.1 yallist: 3.1.1
magic-string-ast@0.9.1:
dependencies:
magic-string: 0.30.17
magic-string@0.27.0: magic-string@0.27.0:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0
@ -9387,6 +9489,12 @@ snapshots:
mlly: 1.7.4 mlly: 1.7.4
pathe: 2.0.3 pathe: 2.0.3
pkg-types@2.1.0:
dependencies:
confbox: 0.2.2
exsolve: 1.0.5
pathe: 2.0.3
pkg-up@3.1.0: pkg-up@3.1.0:
dependencies: dependencies:
find-up: 3.0.0 find-up: 3.0.0
@ -9489,6 +9597,8 @@ snapshots:
punycode@2.3.1: {} punycode@2.3.1: {}
quansync@0.2.10: {}
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}
read-cache@1.0.0: read-cache@1.0.0:
@ -10138,6 +10248,11 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
unplugin-utils@0.2.4:
dependencies:
pathe: 2.0.3
picomatch: 4.0.2
unplugin-vue-components@0.22.12(@babel/parser@7.27.5)(rollup@3.29.5)(vue@3.5.13(typescript@4.9.5)): unplugin-vue-components@0.22.12(@babel/parser@7.27.5)(rollup@3.29.5)(vue@3.5.13(typescript@4.9.5)):
dependencies: dependencies:
'@antfu/utils': 0.7.10 '@antfu/utils': 0.7.10
@ -10157,11 +10272,25 @@ snapshots:
- rollup - rollup
- supports-color - supports-color
unplugin-vue-define-options@3.0.0-beta.14(vue@3.5.13(typescript@4.9.5)):
dependencies:
'@vue-macros/common': 3.0.0-beta.14(vue@3.5.13(typescript@4.9.5))
ast-walker-scope: 0.8.1
unplugin: 2.3.5
transitivePeerDependencies:
- vue
unplugin@1.16.1: unplugin@1.16.1:
dependencies: dependencies:
acorn: 8.14.0 acorn: 8.14.0
webpack-virtual-modules: 0.6.2 webpack-virtual-modules: 0.6.2
unplugin@2.3.5:
dependencies:
acorn: 8.14.1
picomatch: 4.0.2
webpack-virtual-modules: 0.6.2
update-browserslist-db@1.1.2(browserslist@4.24.4): update-browserslist-db@1.1.2(browserslist@4.24.4):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
@ -10268,6 +10397,15 @@ snapshots:
dependencies: dependencies:
clipboard: 2.0.11 clipboard: 2.0.11
vue-cropper-h5@2.0.1(typescript@4.9.5):
dependencies:
vue: 3.5.13(typescript@4.9.5)
vue-cropper: 1.1.4
transitivePeerDependencies:
- typescript
vue-cropper@1.1.4: {}
vue-cropperjs@5.0.0(vue@3.5.13(typescript@4.9.5)): vue-cropperjs@5.0.0(vue@3.5.13(typescript@4.9.5)):
dependencies: dependencies:
cropperjs: 1.6.2 cropperjs: 1.6.2

75
src/api/badge.ts

@ -1,15 +1,64 @@
import request from '@/utils/request' import request from '@/utils/request'
// export const calc = (data: any) => { // 获取杂图
// return request('queue/calc', { export const getSundryList = (params: any) => {
// method: 'POST', return request('products/sundryList', {
// data, method: 'GET',
// }) params,
// } })
}
// export const attr = (params: any) => {
// return request('queue/attr', { // 获取风格类型
// method: 'GET', export const getKindList = (params: any) => {
// params, return request('products/kindList', {
// }) method: 'GET',
// } params,
})
}
// 获取上传图片地址
export const getImageUrl = (params: any) => {
return request('images/uploadUrl', {
method: 'GET',
params,
})
}
// 获取图片
export const getImageList = (params: any) => {
return request('images/getList', {
method: 'GET',
params,
})
}
// 获取记录图集
export const getLogOage = (params: any) => {
return request('images/logPage', {
method: 'GET',
params,
})
}
// 获取我的订单
export const getMyOrder = (params: any) => {
return request('orders/page', {
method: 'GET',
params,
})
}
// 获取订单详情
export const getOrderDetail = (params: any) => {
return request('orders/details', {
method: 'GET',
params,
})
}
export const putMOdeling = (data: any) => {
return request('images/putModeling', {
method: 'POST',
data,
})
}

2
src/config/config.ts

@ -1,3 +1,3 @@
export const config: any = { export const config: any = {
brand: '3D摄影', brand: '葡啊立体肖像',
} }

2
src/lang/data/en.ts

@ -71,7 +71,7 @@ const en = {
"人请等待叫号": "people ahead of you, please wait for your turn.", "人请等待叫号": "people ahead of you, please wait for your turn.",
"返回": "Go back", "返回": "Go back",
"排队成功": "Queue successful", "排队成功": "Queue successful",
"3D摄影": "3D Photography", "葡啊立体肖像": "3D Photography",
"排队": "Queue", "排队": "Queue",
"登录": "Login", "登录": "Login",
"客户手机号和客户编号不能同时为空": "The customer's phone number and customer ID cannot both be empty at the same time.", "客户手机号和客户编号不能同时为空": "The customer's phone number and customer ID cannot both be empty at the same time.",

2
src/lang/data/ko.ts

@ -70,7 +70,7 @@ const ko = {
"人请等待叫号": "명이 있습니다. 호출을 기다려 주세요", "人请等待叫号": "명이 있습니다. 호출을 기다려 주세요",
"返回": "돌아오다", "返回": "돌아오다",
"排队成功": "줄을 서서 성공하다", "排队成功": "줄을 서서 성공하다",
"3D摄影": "3D 촬영", "葡啊立体肖像": "3D 촬영",
"排队": "줄을 서다", "排队": "줄을 서다",
"登录": "로그인", "登录": "로그인",
"客户手机号和客户编号不能同时为空": "고객 휴대폰 번호와 고객 번호는 동시에 비워 둘 수 없습니다", "客户手机号和客户编号不能同时为空": "고객 휴대폰 번호와 고객 번호는 동시에 비워 둘 수 없습니다",

2
src/lang/data/zh-CN.ts

@ -70,7 +70,7 @@ const zhCN = {
"人请等待叫号": "人请等待叫号", "人请等待叫号": "人请等待叫号",
"返回": "返回", "返回": "返回",
"排队成功": "排队成功", "排队成功": "排队成功",
"3D摄影": "3D摄影", "葡啊立体肖像": "葡啊立体肖像",
"排队": "排队", "排队": "排队",
"登录": "登录", "登录": "登录",
"客户手机号和客户编号不能同时为空": "客户手机号和客户编号不能同时为空", "客户手机号和客户编号不能同时为空": "客户手机号和客户编号不能同时为空",

2
src/lang/data/zh-TW.ts

@ -69,7 +69,7 @@ const zhCT = {
"人请等待叫号": "人請等待叫號", "人请等待叫号": "人請等待叫號",
"返回": "返回", "返回": "返回",
"排队成功": "排隊成功", "排队成功": "排隊成功",
"3D摄影": "3D攝影", "葡啊立体肖像": "3D攝影",
"排队": "排隊", "排队": "排隊",
"登录": "登錄", "登录": "登錄",
"客户手机号和客户编号不能同时为空": "客户手機號碼與客戶編號不能同時為空", "客户手机号和客户编号不能同时为空": "客户手機號碼與客戶編號不能同時為空",

42
src/router/index.ts

@ -4,9 +4,7 @@ import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
// 导入路由组件 // 导入路由组件
import * as badgeRouter from './badge' import * as badgeRouter from './badge'
import mian from '@/views/index.vue' import badge from '@/views/badge/index.vue'
import Login from '@/views/login/index.vue'
import { useTokenStore } from '@/stores/token'
import {useStore} from '@/stores' import {useStore} from '@/stores'
import { config } from '@/config/config' import { config } from '@/config/config'
@ -16,21 +14,13 @@ NProgress.configure({ showSpinner: true, parent: '#app' })
const routes = [ const routes = [
{ {
path: '/', path: '/',
name: 'main', name: 'badge',
component: mian, component: badge,
meta: { meta: {
needGuard: true, needGuard: true,
title: '首页', title: '首页',
}, },
}, },
{
path: '/login',
name: 'login',
component: Login,
meta: {
title: '登录',
},
},
] ]
badgeRouter.mergeRoutes(routes) badgeRouter.mergeRoutes(routes)
@ -41,11 +31,10 @@ const router = createRouter({
}) })
router.beforeEach((_to, _from, next) => { router.beforeEach((_to, _from, next) => {
const tokenStore = useTokenStore() // const tokenStore = useTokenStore()
const store = useStore() const store = useStore()
const token = _to.query.token const code = _to.query.code
if (token) { if (code) {
tokenStore.login(String(token))
let url = store.redirectUrl() let url = store.redirectUrl()
if (_to.path !== '/badge') { if (_to.path !== '/badge') {
@ -67,29 +56,10 @@ router.beforeEach((_to, _from, next) => {
NProgress.start() // start progress bar NProgress.start() // start progress bar
const needGuard = _to.meta.needGuard const needGuard = _to.meta.needGuard
if (needGuard) { if (needGuard) {
if (!tokenStore.isLoggedIn()) {
// 记录本地访问路径
store.setRedirect(_to.fullPath);
next(`/login`)
} else {
if (_to.path === '/') {
next('/badge')
} else {
next()
}
}
} else {
if (_to.path === '/login') {
if (!tokenStore.isLoggedIn()) {
next() next()
} else {
next('/badge')
}
} else { } else {
next() next()
} }
}
}) })
router.afterEach(() => { router.afterEach(() => {

329
src/views/badge/cropper.vue

@ -1,329 +0,0 @@
<script lang="ts">
import { defineComponent } from '@vue/runtime-dom'
import type { PropType } from '@vue/runtime-dom'
interface Style {
width?: string
height?: string
top?: string
left?: string
[key: string]: any
}
const tabHeight = 70
export default defineComponent({
name: 'Cropper',
props: {
avatarSrc: {
type: String as PropType<string>,
default: '',
},
avatarStyle: {
type: String as PropType<string>,
default: '',
},
selWidth: {
type: String as PropType<string>,
default: '',
},
selHeight: {
type: String as PropType<string>,
default: '',
},
expWidth: {
type: String as PropType<string>,
default: '',
},
expHeight: {
type: String as PropType<string>,
default: '',
},
minScale: {
type: String as PropType<string>,
default: '',
},
maxScale: {
type: String as PropType<string>,
default: '',
},
canScale: {
type: String as PropType<string>,
default: '',
},
noTab: {
type: String as PropType<string>,
default: '',
},
quality: {
type: String as PropType<string>,
default: '',
},
index: {
type: String as PropType<string>,
default: '',
},
},
data() {
return {
cvsStyleHeight: '0px',
styleDisplay: 'none',
styleTop: '-10000px',
prvTop: '-10000px',
imgStyle: {} as Style,
selStyle: {} as Style,
showOper: true,
imgSrc: {
imgSrc: '',
},
qlty: 0.9,
postWidthFirst: {},
}
},
watch: {
avatarSrc() {
this.imgSrc.imgSrc = this.avatarSrc
},
},
created() {
const canvas = document.getElementById('avatar-canvas')
const operCanvas = document.getElementById('oper-canvas')
this.ctxCanvas = canvas.getContext('2d')
this.ctxCanvasOper = operCanvas.getContext('2d')
this.qlty = parseInt(this.quality) || 0.9
this.imgSrc.imgSrc = this.avatarSrc
this.letScale = this.canScale === 'false' ? 0 : 1
this.indx = this.index || undefined
this.mnScale = this.minScale || 0.3
this.mxScale = this.maxScale || 4
this.noBar = this.noTab === 'true' ? 1 : 0
if (this.noBar) {
this.moreHeight = 0
this.fWindowResize()
} else {
this.moreHeight = 50
this.fWindowResize()
}
},
methods: {
fWindowResize() {
const sysInfo = {
platform: navigator.platform,
pixelRatio: window.devicePixelRatio,
windowWidth: window.innerWidth,
windowHeight: window.innerHeight,
windowTop: window.scrollY,
windowBottom: 0,
statusBarHeight: 0,
screenHeight: screen.height,
}
this.platform = sysInfo.platform
this.pixelRatio = sysInfo.pixelRatio
this.windowWidth = sysInfo.windowWidth
this.drawTop = sysInfo.windowTop
this.windowHeight = sysInfo.windowHeight + sysInfo.windowBottom
this.cvsStyleHeight = `${this.windowHeight - tabHeight}px`
this.pxRatio = this.windowWidth / 750
const style = this.avatarStyle
console.log(style)
this.imgStyle = style
this.expWidth && (this.exportWidth = this.expWidth.includes('rpx')
? parseInt(this.expWidth) * this.pxRatio
: parseInt(this.expWidth))
this.expHeight && (this.exportHeight = this.expHeight.includes('rpx')
? parseInt(this.expHeight) * this.pxRatio
: parseInt(this.expHeight))
if (this.styleDisplay === 'flex')
this.fDrawInit(true)
this.fHideImg()
},
fSelect() {
if (this.fSelecting)
return
this.fSelecting = true
setTimeout(() => {
this.fSelecting = false
}, 500)
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'
input.onchange = (e) => {
const file = e.target.files[0]
if (!file)
return
const reader = new FileReader()
reader.onload = (e) => {
const path = e.target.result
this.imgPath = path
const img = new Image()
img.onload = () => {
this.imgWidth = img.width
this.imgHeight = img.height
this.path = path
if (!this.hasSel) {
const style = this.selStyle || {}
if (this.selWidth && this.selHeight) {
const selWidth = this.selWidth.includes('rpx')
? parseInt(this.selWidth) * this.pxRatio
: parseInt(this.selWidth)
const selHeight = this.selHeight.includes('rpx')
? parseInt(this.selHeight) * this.pxRatio
: parseInt(this.selHeight)
style.width = `${parseInt(selWidth)}px`
style.height = `${parseInt(selHeight)}px`
style.top = `${parseInt((this.windowHeight - parseInt(style.height) - tabHeight) / 2)}px`
style.left = `${parseInt((this.windowWidth - parseInt(style.width)) / 2)}px`
} else {
alert('裁剪框的宽或高没有设置')
return
}
this.selStyle = style
}
this.fDrawInit(true)
}
img.src = path
}
reader.readAsDataURL(file)
}
input.click()
},
fUpload() {
if (this.fUploading)
return
this.fUploading = true
setTimeout(() => {
this.fUploading = false
}, 1000)
const style = this.selStyle
let x = parseInt(style.left)
let y = parseInt(style.top)
const width = parseInt(style.width)
const height = parseInt(style.height)
let expWidth = this.exportWidth || width
let expHeight = this.exportHeight || height
x *= this.pixelRatio
y *= this.pixelRatio
expWidth = width
expHeight = height
this.styleDisplay = 'none'
this.styleTop = '-10000px'
this.hasSel = false
this.fHideImg()
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
const ctx = canvas.getContext('2d')
ctx.drawImage(this.ctxCanvas.canvas, x, y, width, height, 0, 0, expWidth, expHeight)
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob)
this.$emit('upload', {
avatar: this.imgSrc,
path: url,
index: this.indx,
})
}, 'image/png', this.qlty)
},
// ...
},
})
</script>
<template name="cropper">
<view>
<image :src="imgSrc.imgSrc" class="my-avatar" mode="aspectFill" :style="imgStyle" @click="fSelect" />
<!-- 上传图片 -->
<canvas
id="avatar-canvas" canvas-id="avatar-canvas" class="my-canvas" :style="{ top: styleTop, height: cvsStyleHeight }"
disable-scroll="false"
/>
<!-- 截取边框 -->
<canvas
id="oper-canvas" canvas-id="oper-canvas" class="oper-canvas" :style="{ top: styleTop, height: cvsStyleHeight }"
disable-scroll="false" @touchstart="fStart" @touchmove="fMove" @touchend="fEnd"
/>
<view class="oper-wrapper" :style="{ display: styleDisplay }">
<view v-if="showOper" class="btn-wrapper">
<view hover-class="hover" @click="fClose">
取消
</view>
<view hover-class="hover" @click="fUpload">
选取
</view>
</view>
</view>
</view>
</template>
<style lang="less">
.my-canvas {
display: flex;
position: fixed !important;
background: #000000;
left: 0;
z-index: 100;
width: 100%;
}
.my-avatar {
width: 100vw;
height: 100vw;
}
.oper-canvas {
display: flex;
position: fixed !important;
left: 0;
z-index: 101;
width: 100%;
}
.oper-wrapper {
height: 71px;
position: fixed !important;
box-sizing: border-box;
width: 100%;
left: 0;
bottom: 0;
z-index: 200;
flex-direction: row;
}
.btn-wrapper {
background-color: #000000;
color: #ffffff;
display: flex;
height: 100%;
width: 100%;
justify-content: space-around;
align-items: center;
}
.btn-wrapper view {
width: 160rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
font-size: 16px;
color: #ffffff;
z-index: 300;
}
.hover {
color: #f1f1f1;
}
</style>

153
src/views/badge/index.vue

@ -1,19 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import H5Cropper from 'vue-cropper-h5'
import "vue-cropper-h5/dist/style.css"
import * as badgeApi from '@/api/badge'
import { onMounted, ref } from 'vue';
const show = ref(false) const show = ref(false)
const imgShow = ref(false) const imgShow = ref(false)
const router = useRouter() const router = useRouter()
const imgurl = ref('') // const option = ref({})
const fileInput = ref<HTMLInputElement | null>(null) const options = ref({})
function onUploadClick() { const imgurl = ref('')
if (fileInput.value) const imgBgUrl = ref('')
fileInput.value.click() const isBgShow = ref(true)
}
function myUpload(rsp) {
const self = this
self.imgurl = rsp.path //
}
function goToRecord() { function goToRecord() {
router.push('/badge/record') router.push('/badge/record')
} }
@ -23,7 +22,59 @@ function goToMyOrder() {
function goToPreview() { function goToPreview() {
router.push('/badge/preview') router.push('/badge/preview')
} }
function onFileChange function getbase64Data(data) {
imgurl.value = data;
console.log('图片地址', data)
}
function getBgbase64Data(data) {
imgBgUrl.value = data;
console.log('背景图片地址', data)
}
const getKindList = () => {
badgeApi.getKindList({
page: 1,
size: 20,
scale: 20,
}).then((res: any) => {
const data = res || []
}).catch((err) => {
}).finally((err) => {
})
}
const getSundryList = () => {
badgeApi.getSundryList({
page: 1,
size: 6,
group: 'gp',
}).then((res: any) => {
const data = res || []
}).catch((err) => {
}).finally((err) => {
})
}
const getList = () => {
badgeApi.getSundryList({
page: 1,
size: 5,
group: 'case',
ids: '6,7,8,9,19'
}).then((res: any) => {
const data = res || []
}).catch((err) => {
}).finally((err) => {
})
}
onMounted(() => {
getKindList()
getSundryList()
getList()
})
</script> </script>
<template> <template>
@ -98,19 +149,13 @@ function onFileChange
</div> </div>
</div> </div>
</div> </div>
<div class="photo-upload-box"> <div class="photo-upload-body">
<div v-if="!imgurl" class="photo-upload-box">
<div class="photo-upload-header" @click="imgShow = true"> <div class="photo-upload-header" @click="imgShow = true">
<van-icon name="question-o" size="16px" class="photo-upload-guide-icon" /> <van-icon name="question-o" size="16px" class="photo-upload-guide-icon" />
<span class="photo-upload-guide-text">图片上传指南</span> <span class="photo-upload-guide-text">图片上传指南</span>
</div> </div>
<div class="photo-upload-area" @click="onUploadClick"> <div class="photo-upload-area">
<input
ref="fileInput"
type="file"
accept="image/*"
style="display: none"
@change="onFileChange"
>
<div class="photo-upload-plus"> <div class="photo-upload-plus">
+ +
</div> </div>
@ -125,6 +170,11 @@ function onFileChange
请确定您对上传的照片拥有合法使用权利或已取得他人合法授权且同意本平台分析图片信息以提供生成服务 请确定您对上传的照片拥有合法使用权利或已取得他人合法授权且同意本平台分析图片信息以提供生成服务
</div> </div>
</div> </div>
<img class="photo-upload-img" v-if="imgurl" :src="imgurl" alt="" srcset="">
<div class="photo-upload-box-1">
<h5-cropper :option="option" @getbase64Data="getbase64Data"></h5-cropper>
</div>
</div>
<div class="style-section"> <div class="style-section">
<div class="style-title"> <div class="style-title">
风格样式 风格样式
@ -198,38 +248,40 @@ function onFileChange
</div> </div>
<div class="bg-style-tabs"> <div class="bg-style-tabs">
<button <button
class="bg-style-tab active" class="bg-style-tab" :class="isBgShow == true ? 'active' : ''"
type="button" type="button" @click="isBgShow = true"
> >
照片原图背景 照片原图背景
</button> </button>
<button <button
class="bg-style-tab" class="bg-style-tab" :class="isBgShow == false ? 'active' : ''"
type="button" type="button" @click="isBgShow = false"
disabled
> >
补充背景照片 补充背景照片
</button> </button>
</div> </div>
<div class="bg-style-tip"> <div v-if="isBgShow == true" class="bg-style-tip">
选择该选项设计的徽章会根据上传的肖像照片背景进行生成效果 选择该选项设计的徽章会根据上传的肖像照片背景进行生成效果
</div> </div>
<div class="bg-style-tip"> <div v-if="isBgShow == false" class="bg-style-tip">
选择该选项需要额外上传一张照片作为背景 选择该选项需要额外上传一张照片作为背景
</div> </div>
</div> </div>
<div class="bg-photo-upload-section"> <div class="bg-photo-upload-section" v-if="isBgShow == false">
<div class="bg-photo-upload-header"> <div class="bg-photo-upload-header">
<span>补充背景照片</span> <span>补充背景照片</span>
</div> </div>
<div class="bg-photo-upload-area"> <div class="bg-photo-upload-area">
<label class="bg-photo-upload-label"> <div v-if="!imgBgUrl" class="bg-photo-upload-label">
<input type="file" accept="image/*" style="display:none">
<div class="bg-photo-upload-box"> <div class="bg-photo-upload-box">
<div class="bg-photo-upload-plus">+</div> <div class="bg-photo-upload-plus">+</div>
<div class="bg-photo-upload-text">上传照片</div> <div class="bg-photo-upload-text">上传照片</div>
</div> </div>
</label> </div>
<img v-if="imgBgUrl" class="bg-photo-upload-img" :src="imgBgUrl" alt="">
<div class="bg-photo-upload-label-1">
<h5-cropper :option="options" @getbase64Data="getBgbase64Data"></h5-cropper>
</div>
</div> </div>
</div> </div>
<div style="height: 90px;" /> <div style="height: 90px;" />
@ -477,6 +529,12 @@ function onFileChange
margin-top: 2px; margin-top: 2px;
} }
.photo-upload-body {
position: relative;
width: 80vw;
height: 80vw;
margin: 16px auto 0 auto;
}
.photo-upload-box { .photo-upload-box {
margin: 16px auto 0 auto; margin: 16px auto 0 auto;
width: 80vw; width: 80vw;
@ -489,6 +547,22 @@ function onFileChange
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
} }
.photo-upload-box-1 {
width: 80vw;
height: 70vw;
border-radius: 12px;
/* background: #F0F2F5; */
background: rgba(0, 0, 0, 0);
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.photo-upload-img {
width: 80vw;
height: 80vw;
border-radius: 12px;
}
.photo-upload-header { .photo-upload-header {
width: 100%; width: 100%;
display: flex; display: flex;
@ -687,10 +761,20 @@ function onFileChange
.bg-photo-upload-area { .bg-photo-upload-area {
display: flex; display: flex;
align-items: center; align-items: center;
position: relative;
} }
.bg-photo-upload-label { .bg-photo-upload-label {
display: inline-block; display: inline-block;
} }
.bg-photo-upload-label-1 {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 120px;
height: 120px;
background: none;
}
.bg-photo-upload-box { .bg-photo-upload-box {
width: 120px; width: 120px;
height: 120px; height: 120px;
@ -704,6 +788,11 @@ function onFileChange
background: #fafafa; background: #fafafa;
transition: border 0.2s; transition: border 0.2s;
} }
.bg-photo-upload-img {
width: 120px;
height: 120px;
border-radius: 12px;
}
.bg-photo-upload-plus { .bg-photo-upload-plus {
font-size: 32px; font-size: 32px;
color: #b0b0b0; color: #b0b0b0;

45
src/views/badge/myOrder.vue

@ -1,10 +1,10 @@
<template> <template>
<div class="my-order"> <div class="my-order">
<div class="header" @click="goBack"> <div class="header" @click="goBack">
<span class="back-icon"><van-icon name="arrow-left" size="16px" /> 返回</span> <span class="back-icon"><van-icon name="arrow-left" size="16px" color="#333" /> 我的订单</span>
</div> </div>
<div class="order-list"> <div class="order-list">
<div class="order-item" @click="OrderDetail"> <div class="order-item" @click="OrderDetail(item.id)" v-for="item in orders" :key="item.id">
<img class="order-img" src="@/assets/badge/suiji.png" alt="order1" /> <img class="order-img" src="@/assets/badge/suiji.png" alt="order1" />
<span class="order-status status-processing">生产中</span> <span class="order-status status-processing">生产中</span>
</div> </div>
@ -16,13 +16,48 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router'
import * as badgeApi from '@/api/badge'
import { onMounted, ref } from 'vue'
const page = ref(1)
const loading = ref(false)
const finished = ref(false)
const orders = ref([])
onMounted(() => {
getOrder()
})
function getOrder() {
if(loading.value) return
loading.value = true
badgeApi.getMyOrder({
page: page.value,
pageSize: 10,
}).then(res => {
if(page.value === 1) {
orders.value = res.data.list
} else {
orders.value.push(...res.data.list)
}
if(res.data.list.length < 10) {
finished.value = true
} else {
page.value++
}
}).finally(() => {
loading.value = false
})
}
const router = useRouter(); const router = useRouter();
function goBack() { function goBack() {
router.push('/badge'); router.push('/badge');
} }
function OrderDetail() { function OrderDetail(id: number) {
router.push('/badge/orderDetail') router.push({
path: '/badge/orderDetail',
query: {
id: id,
},
})
} }
</script> </script>
<style scoped> <style scoped>

20
src/views/badge/orderDetail.vue

@ -1,7 +1,7 @@
<template> <template>
<div class="my-order"> <div class="my-order">
<div class="header" @click="goBack"> <div class="header" @click="goBack">
<span class="back-icon"><van-icon name="arrow-left" size="16px" /> 返回</span> <span class="back-icon"><van-icon name="arrow-left" size="16px" color="#333" /> 订单详情</span>
</div> </div>
<div class="order-status"> <div class="order-status">
<div class="avatar-wrapper"> <div class="avatar-wrapper">
@ -68,8 +68,24 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import * as badgeApi from '@/api/badge';
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
const order = ref({})
const id = ref(0)
onMounted(() => {
id.value = route.query.id
getOrderDetail()
})
function getOrderDetail() {
badgeApi.getOrderDetail({
id: id.value,
}).then(res => {
order.value = res.data
})
}
const router = useRouter(); const router = useRouter();
function goBack() { function goBack() {
router.push('/badge/myOrder'); router.push('/badge/myOrder');

295
src/views/badge/preview.vue

@ -20,13 +20,16 @@
</div> </div>
</div> </div>
</div> </div>
<div class="progress-section"> <div v-if="!imageUrl" class="progress-section">
<div class="progress-bar-bg"> <div class="progress-bar-bg">
<div class="progress-bar-fg" :style="{ width: '12%' }"></div> <div class="progress-bar-fg" :style="{ width: progress + '%' }"></div>
</div> </div>
<div class="progress-text">照片数据分析中 12%</div> <div class="progress-text">照片数据分析中 {{progress}}%</div>
<div class="progress-desc">总计大约需要60秒请耐心等待...</div> <div class="progress-desc">总计大约需要60秒请耐心等待...</div>
</div> </div>
<div v-else class="progress-section">
<img class="progress-section-img" :src="imageUrl" alt="">
</div>
<div class="info-section"> <div class="info-section">
<div class="info-item"> <div class="info-item">
<div class="info-title">芯比风格</div> <div class="info-title">芯比风格</div>
@ -54,40 +57,230 @@
<span class="order-size">4cm</span> <span class="order-size">4cm</span>
<span class="order-free">(剩余兑换1)</span> <span class="order-free">(剩余兑换1)</span>
<div class="order-ctrl"> <div class="order-ctrl">
<button class="order-btn" disabled>-</button> <van-stepper v-model="value" @change="changeValue" />
<span class="order-count">1</span>
<button class="order-btn">+</button>
</div> </div>
</div> </div>
<div class="order-item"> <div class="order-item">
<span class="order-size">5cm</span> <span class="order-size">5cm</span>
<span class="order-free">(剩余兑换2)</span> <span class="order-free">(剩余兑换2)</span>
<div class="order-ctrl"> <div class="order-ctrl">
<button class="order-btn" disabled>-</button> <van-stepper v-model="value" />
<span class="order-count">1</span>
<button class="order-btn">+</button>
</div> </div>
</div> </div>
</div> </div>
<div class="confirm-box"> <div class="confirm-box">
<div class="action-section"> <div class="action-section">
<button class="action-btn"><img class="action-img" src="@/assets/badge/reload.png" alt=""> 再次生成</button> <button @click="showReload = true" class="action-btn"><img class="action-img" src="@/assets/badge/reload.png" alt=""> 再次生成</button>
<button class="action-btn"><img class="action-img" src="@/assets/badge/duibi.png" alt=""> 前后对比</button> <button @click="compare" :disabled="flag < 2" class="action-btn"><img class="action-img" src="@/assets/badge/duibi.png" alt=""> 前后对比</button>
<button class="action-btn"><img class="action-img" src="@/assets/badge/down.png" alt=""> 保存图片</button> <button @click="save" :disabled="flag < 2" class="action-btn"><img class="action-img" src="@/assets/badge/down.png" alt=""> 保存图片</button>
</div> </div>
<div class="btn-box"> <div class="btn-box">
<button class="confirm-btn">确认选择</button> <button @click="confirm" :disabled="flag < 2" class="confirm-btn">确认选择</button>
</div>
</div>
</div>
<van-action-sheet v-model:show="showReload" title="风格样式选择" :close-on-click-overlay="true" closeable>
<div class="style-selection">
<div class="style-grid">
<div class="style-item" :class="{'active': style == 'suiji'}" @click="changeStyle('suiji')">
<img src="@/assets/badge/suiji.png" alt="随机风格盲盒" class="style-img">
<div class="style-label">随机风格盲盒</div>
<span class="style-selected" v-if="style == 'suiji'" style="display: inline-block;">
<van-icon name="checked" color="#50cf54" size="21px" />
</span>
</div>
<div class="style-item" :class="{'active': style == 'qban'}" @click="changeStyle('qban')">
<img src="@/assets/badge/suiji.png" alt="Q版国风动漫" class="style-img">
<div class="style-label">Q版国风动漫</div>
<span class="style-selected" v-if="style == 'qban'">
<van-icon name="checked" color="#50cf54" size="21px" />
</span>
</div>
<div class="style-item" :class="{'active': style == 'qkant'}" @click="changeStyle('qkant')">
<img src="@/assets/badge/suiji.png" alt="Q版卡通" class="style-img">
<div class="style-label">Q版卡通</div>
<span class="style-selected" v-if="style == 'qkant'">
<van-icon name="checked" color="#50cf54" size="21px" />
</span>
</div>
<div class="style-item" :class="{'active': style == 'babifeng'}" @click="changeStyle('babifeng')">
<img src="@/assets/badge/suiji.png" alt="芭比风" class="style-img">
<div class="style-label">芭比风</div>
<span class="style-selected" v-if="style == 'babifeng'">
<van-icon name="checked" color="#50cf54" size="21px" />
</span>
</div>
<div class="style-item">
<img src="@/assets/badge/suiji.png" alt="迪士尼皮克斯" class="style-img">
<div class="style-label">迪士尼皮克斯</div>
</div>
<div class="style-item">
<img src="@/assets/badge/suiji.png" alt="写实肖像" class="style-img">
<div class="style-label">写实肖像</div>
</div>
</div>
<div class="confirm-wrapper">
<button class="confirm-button">
确认再次生成
</button>
</div>
</div>
</van-action-sheet>
<van-action-sheet v-model:show="showCompare" title="前后对比" :close-on-click-overlay="true" closeable>
<div style="padding: 16px;">
<div style="display: flex; align-items: center; justify-content: center; gap: 20px;">
<div style="text-align: center;">
<img src="@/assets/badge/suiji.png" alt="随机风格盲盒" style="width: 120px; height: 120px; border-radius: 8px;">
</div>
<div style="font-size: 24px; color: #333;">
<van-icon name="arrow" size="20px" />
</div>
<div style="text-align: center;">
<img src="@/assets/badge/suiji.png" alt="随机风格盲盒" style="width: 120px; height: 120px; border-radius: 8px;">
</div>
</div>
<div style="text-align: center; margin-top: 16px; color: #999; font-size: 12px;">
温馨提示<br/>
AI设计的徽章效果图是根据用户提供的照片机器学习生成的<br/>
多试几次就能找到你满意的徽章~
</div>
</div>
</van-action-sheet>
<van-action-sheet v-model:show="showBgCompare" title="前后对比" :close-on-click-overlay="true" closeable>
<div style="padding: 16px;">
<div style="display: flex; align-items: center; justify-content: center; gap: 20px;">
<div style="text-align: center;">
<img src="@/assets/badge/suiji.png" alt="背景对比图" style="width: 120px; height: 120px; border-radius: 8px;">
</div>
<div style="font-size: 24px; color: #333;">
<van-icon name="plus" size="20px" />
</div> </div>
<div style="text-align: center;">
<img src="@/assets/badge/suiji.png" alt="背景对比图" style="width: 120px; height: 120px; border-radius: 8px;">
</div> </div>
</div> </div>
<div style="font-size: 24px; color: #333;display: flex; align-items: center; justify-content: center; margin: 16px 0;">
<van-icon name="arrow-down" size="20px" />
</div>
<div style="display: flex; align-items: center; justify-content: center; gap: 20px;">
<div style="text-align: center;">
<img src="@/assets/badge/suiji.png" alt="背景对比图" style="width: 120px; height: 120px; border-radius: 8px;">
</div>
</div>
<div style="text-align: center; margin-top: 16px; color: #999; font-size: 12px;">
温馨提示<br/>
AI设计的图案效果图是根据用户提供的照片机器学习生成的<br/>
多试几次就能找到你满意的效果~
</div>
</div>
</van-action-sheet>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import * as badgeApi from '@/api/badge'
const router = useRouter(); const router = useRouter();
const value = ref(0);
const showReload = ref(false)
const showCompare = ref(false)
const showBgCompare = ref(false)
function compare() {
// showCompare.value = true
showBgCompare.value = true
}
function save() {
//
const downloadImage = (url: string) => {
const link = document.createElement('a')
link.href = url
link.download = '徽章效果图.png'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
if (imageUrl.value) {
downloadImage(imageUrl.value)
} else {
showReload.value = true
}
}
const style = ref('suiji')
function changeStyle(style: string) {
console.log(style)
style.value = style
}
function confirm() {
console.log('confirm')
}
function goBack() { function goBack() {
router.push('/badge'); router.push('/badge');
} }
const changeValue = (value: number) => {
console.log(value)
}
const imageUrl = ref('')
const group = ref(1);
//
const flag = ref(1)
const timer = ref()
const progress = ref(0)
const progressTimer = ref()
const progressList = () => {
//
progress.value = 0
if (!progressTimer.value) {
progressTimer.value = setInterval(() => {
if (progress.value < 90) {
progress.value += 1
}
}, 500)
}
}
const getImageList = () => {
badgeApi.getKindList({
pid: 0,
group: group.value
}).then((res: any) => {
const data = res || []
flag.value = data.flag || 1
if (flag.value === 2) {
//
clearInterval(timer.value)
clearInterval(progressTimer.value)
// 100%
progress.value = 100
//
imageUrl.value = data.url
}
}).catch((err) => {
clearInterval(progressTimer.value)
progress.value = 0
}).finally((err) => {
})
}
onMounted(() => {
getImageList()
progressList()
timer.value = setInterval(() => {
getImageList()
}, 10000)
})
onUnmounted(() => {
clearInterval(timer.value)
clearInterval(progressTimer.value)
})
</script> </script>
<style scoped> <style scoped>
.preview-container { .preview-container {
@ -214,6 +407,11 @@ function goBack() {
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
} }
.progress-section-img {
width: 80vw;
height: 80vw;
border-radius: 12px;
}
.progress-bar-bg { .progress-bar-bg {
width: 70%; width: 70%;
height: 10px; height: 10px;
@ -354,9 +552,6 @@ function goBack() {
height: 20px; height: 20px;
margin-right: 5px; margin-right: 5px;
} }
.action-btn:hover {
background: #e6f7ea;
}
.btn-box { .btn-box {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -378,4 +573,70 @@ function goBack() {
.confirm-btn:active { .confirm-btn:active {
background: linear-gradient(90deg, #5ccf7a 0%, #8fdca0 100%); background: linear-gradient(90deg, #5ccf7a 0%, #8fdca0 100%);
} }
.style-selection {
padding: 16px;
}
.style-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.style-item {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
position: relative;
width: 28vw;
}
.style-img {
width: 28vw;
height: 28vw;
border-radius: 8px;
object-fit: cover;
background: #f5f5f5;
border: 2px solid transparent;
transition: border 0.2s;
}
.style-item .style-selected {
position: absolute;
right: 4px;
bottom: 30px;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.style-label {
font-size: 13px;
color: #333;
margin-top: 4px;
}
.confirm-wrapper {
margin-top: 24px;
}
.confirm-button {
width: 100%;
background: linear-gradient(90deg, #D1ED8E 0%, #55E668 100%);
color: #000;
font-size: 17px;
font-weight: 600;
border: none;
border-radius: 24px;
padding: 12px 0;
cursor: pointer;
}
.confirm-button:active {
background: linear-gradient(90deg, #5ccf7a 0%, #8fdca0 100%);
}
.style-item.active .style-img {
border: 2px solid #50cf54;
}
.style-item.active .style-label {
color: #50cf54;
}
</style> </style>

108
src/views/badge/record.vue

@ -1,20 +1,22 @@
<template> <template>
<div> <div>
<div class="header" @click="goBack"> <div class="header" @click="goBack" style="text-align: center;">
<span class="back-icon"><van-icon name="arrow-left" size="16px" /> 返回</span> <span class="back-icon"><van-icon name="arrow-left" size="16px" color="#333" /> 设计记录</span>
</div> </div>
<div class="record-container"> <div class="record-container">
<div class="record-note"> <div class="record-note">可点击效果图进行下单打印</div>
可点击效果图进行下单打印
</div>
<div class="record-images"> <div class="record-images">
<div <div class="record-image-item">
v-for="(item, idx) in images" <img src="@/assets/badge/suiji.png" alt="效果图" style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;">
:key="idx" </div>
@click="onImageClick(item)" <div class="record-image-item">
class="record-image-item" <img src="@/assets/badge/suiji.png" alt="效果图" style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;">
> </div>
<img :src="item" class="record-image" /> <div class="record-image-item">
<img src="@/assets/badge/suiji.png" alt="效果图" style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;">
</div>
<div class="record-image-item">
<img src="@/assets/badge/suiji.png" alt="效果图" style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;">
</div> </div>
</div> </div>
</div> </div>
@ -22,6 +24,43 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import * as badgeApi from '@/api/badge';
import { onMounted, ref } from 'vue';
const images = ref([]);
onMounted(() => {
getList();
});
const page = ref(1)
const loading = ref(false)
const finished = ref(false)
function getList() {
if(loading.value) return
loading.value = true
badgeApi.getLogOage({
page: page.value,
pageSize: 10,
}).then(res => {
if(page.value === 1) {
images.value = res.data.list
} else {
images.value.push(...res.data.list)
}
if(res.data.list.length < 10) {
finished.value = true
} else {
page.value++
}
}).finally(() => {
loading.value = false
})
}
function onLoad() {
getList()
}
const router = useRouter(); const router = useRouter();
function goBack() { function goBack() {
router.push('/badge'); router.push('/badge');
@ -43,51 +82,32 @@ function goBack() {
cursor: pointer; cursor: pointer;
} }
.record-container { .record-container {
max-width: 500px;
margin: 24px auto;
padding: 16px; padding: 16px;
background: #fff;
border-radius: 16px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
} }
.record-note { .record-note {
color: #888; font-size: 12px;
font-size: 14px; color: #999;
margin-bottom: 18px; margin-bottom: 16px;
text-align: center;
} }
.record-images { .record-images {
display: flex; display: grid;
flex-wrap: wrap; grid-template-columns: repeat(2, 1fr);
gap: 24px; gap: 16px;
justify-content: center;
} }
.record-image-item { .record-image-item {
width: 160px; width: 100%;
height: 160px; padding-bottom: 100%;
position: relative;
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
background: #f7f7f7;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer; cursor: pointer;
transition: box-shadow 0.2s;
}
.record-image-item:hover {
box-shadow: 0 4px 16px rgba(0,0,0,0.14);
} }
.record-image-item img {
.record-image { position: absolute;
top: 0;
left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: cover; object-fit: cover;
border-radius: 50%;
display: block;
} }
</style> </style>

29
src/views/login/helpers/transfer.ts

@ -1,29 +0,0 @@
function googleToNormalize(data: any) {
return {
unionid: data.id,
social_type: 'google',
nickname: (data.last_name + data.first_name) || '',
email: data.email || '',
headimgurl: data.thumbnail || '',
}
}
function twitterToNormalize(data: any) {
return {
unionid: data.id_str || data.id,
social_type: 'twitter',
nickname: data.name || '',
email: data.email || '',
headimgurl: data.thumbnail || '',
}
}
export function normalize(socialType: string, data: any) {
switch (socialType) {
case 'google':
return googleToNormalize(data)
case 'twitter':
return twitterToNormalize(data)
}
}

131
src/views/login/index.vue

@ -1,131 +0,0 @@
<script setup lang="ts">
import hello from 'hellojs'
import type { Ref } from 'vue'
import { normalize } from './helpers/transfer'
// import { useUserStore } from '@/stores/user'
import router from '@/router'
import {useStore} from '@/stores'
import { useTokenStore } from '@/stores/token'
import * as authApi from '@/api/auth'
interface Item {
icon: string
name: string
text: string
}
const logins: Ref<Item[]> = ref([
// {
// icon: 'microsoft',
// name: 'windows',
// text: 'windows',
// },
{
icon: 'googleplus',
name: 'google',
text: 'G+',
},
// {
// icon: 'facebook',
// name: 'facebook',
// text: 'Facebook',
// },
// {
// icon: 'apple',
// name: 'apple',
// text: 'apple',
// },
{
icon: 'twitter',
name: 'twitter',
text: 'twitter',
},
// {
// icon: 'wechat',
// name: 'wechat',
// text: 'wechat',
// },
])
function onBtn(item: Item) {
switch (item.name) {
case 'wechat':
window.location.href = `https://wechat.api.suwa3d.com/api/auth/page?callback${encodeURIComponent(window.location.href)}`
return
}
hello(item.name).login().then((d: any) => {
console.log('d', d)
// hello(item.name).api('me').then((d: any) => {
// console.log('d', d)
// const data: any = normalize(item.name, d)
// // const user = useUserStore()
// // user.login(d)
// // useRouter().replace('/')
// }, (e: any) => {
// console.log('/me error', e)
// })
}, () => {
// console.log('login failed')
})
}
const stores = useStore();
hello.on('auth.login', (r: any) => {
hello(r.network).api('/me', 'get').then((d) => {
const data: any = normalize(r.network, d)
authApi.getUser(data).then((res: any) => {
useTokenStore().login(res)
let url = stores.redirectUrl();
if (url) {
stores.setRedirect('')
router.replace(url)
return
}
router.replace('/')
}, (e: any) => {
console.log('auth.login /me error', e)
})
})
})
// TODO:
hello.init({
facebook: '1875721406193406',
windows: '000000004403AD10',
google: '495792315385-mj44iuov1bupumvl6evmmcvag39mi38t.apps.googleusercontent.com',
twitter: 'ICw3GtdIivmHPI5qTLD0gZDbN',
}, {
redirect_uri: './oauth.html',
scope: 'email',
})
</script>
<template>
<div class="container">
<van-divider>Social Login</van-divider>
<div v-for="(item, i) in logins" :key="i" class="l-btn">
<van-button plain icon-prefix="iconfont" :icon="item.icon" type="primary" size="large" @click="onBtn(item)">
{{ item.text }}
</van-button>
</div>
</div>
</template>
<style scoped lang="less">
.l-btn{
margin: .4rem;
width: 100%;
}
.container{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
}
</style>
Loading…
Cancel
Save