Compare commits

..

133 Commits

Author SHA1 Message Date
Wayne dc0d0e7a26 0000998
2 years ago
bruce68410 f5fa9cccfa 0000946
2 years ago
Wayne 3a7a91b496 0000969
2 years ago
bruce68410 224ec188ac 授權頁面文字修正、版型示意圖片修改
2 years ago
Wayne 0cb90ffe7e 0000954
2 years ago
Wayne cddada9408 0000954
2 years ago
bruce68410 fcbc94fd2a 0000942
2 years ago
bruce68410 3a6d13162b 0000939
2 years ago
Wayne 2c6c89a3ed 0000933
2 years ago
bruce68410 62b7fb2ef2 預覽頁面高度調整
2 years ago
DESKTOP-8UQ1PPR\09158 7b9d560788 0000930
2 years ago
bruce68410 879fbdc151 0000925
2 years ago
Wayne b194ffd690 修改地區及工作性質問題
2 years ago
bruce68410 78d1e9845b 補上圖片網址輸入欄位
2 years ago
bruce68410 fb7be73a6e 處理錯誤訊息 (改回原本
2 years ago
bruce68410 06c4a5bb4a 將預設的ellipsis關閉
2 years ago
bruce68410 bf4cae338e 處理錯誤訊息
2 years ago
Wayne 8d42353a6c 0000876
2 years ago
Wayne 5c0a63d855 0000880
2 years ago
bruce68410 d56e4f4008 發到LINE的名片,加上版型底圖連結、自我介紹及資源改為5行
2 years ago
DESKTOP-8UQ1PPR\09158 69cee05bec 卡片發布調整
2 years ago
DESKTOP-8UQ1PPR\09158 443acf6cc3 修改人脈資源文字
2 years ago
DESKTOP-8UQ1PPR\09158 a843ef4e57 修改四個版型的預覽文字 (補字)
2 years ago
bruce68410 c6b742e903 預覽圖修改、首頁選單icon修改
2 years ago
Wayne 5843aa3bc1 Merge branch 'dev' into sta
2 years ago
Wayne b62a6a694e 使用proxy,處理cors問題
2 years ago
DESKTOP-8UQ1PPR\09158 e861b4f988 人脈資源文字調整
2 years ago
Wayne 89375c64bd remove console.log
2 years ago
Wayne ce432ada07 0000866
2 years ago
Wayne 3e54bc1e36 會員資料欄位檢驗
2 years ago
Wayne 7d53365d12 0000852
2 years ago
Wayne d19f2426a6 Merge branch 'dev' into sta
2 years ago
Wayne 7ff6f225ae 0000838
2 years ago
Wayne c9661a0dc0 會員開通
2 years ago
Wayne 163ef76626 nfc連結及hide版型
2 years ago
Wayne 2951358fcd 0000838
2 years ago
Wayne 3cf93201e3 會員開通
2 years ago
Wayne 355e65749a nfc連結及hide版型
2 years ago
Wayne 822ba3c881 nfc連結
2 years ago
Wayne 30a5f6c53b 版型修改
2 years ago
Wayne 6c6ff6fcd4 0000835
2 years ago
Wayne 3e2df10116 0000833
2 years ago
Wayne f7515aab19 0000826
2 years ago
Wayne 486aa23da7 0000827
2 years ago
Wayne aa59a1068f 0000815,未登入時需先登入
2 years ago
Wayne db77b14659 0000815,未登入時需先登入
2 years ago
Wayne 370963f653 0000815
2 years ago
Wayne 1fc1dfd7a7 0000815
2 years ago
Wayne 54bbae189b 0000801
2 years ago
Wayne 53daffd285 0000812
2 years ago
Wayne 088dca0355 0000810
2 years ago
Wayne 46a1611f76 0000811
2 years ago
Wayne e9dfe78ea9 0000813
2 years ago
Wayne e4e8d5d13a 0000813
2 years ago
Wayne daa3c8145a 0000803
2 years ago
Wayne 46a3998f09 0000802
2 years ago
Wayne d0930be7d1 0000804
2 years ago
Wayne 24383d4ead 經銷商提供會員註冊
2 years ago
Wayne 8da54e528e 註冊時帶上經銷代碼
2 years ago
DESKTOP-8UQ1PPR\09158 a14c38747f 調整代客&授權編輯頁面css
2 years ago
DESKTOP-8UQ1PPR\09158 105440ea8d 標頭層級調整
2 years ago
Wayne d3ad65cea7 修改會員資料bug
2 years ago
Wayne f1d3ad7dc9 影片廣告bug
2 years ago
Wayne 00a3369baf 修正通訊錄類別更改後,id值沒改變問題
2 years ago
Wayne 50a156e16a 通訊錄 - 設定類別後更新
2 years ago
Wayne a56c5470e2 通訊錄 - 設定類別後更新
2 years ago
Wayne 8033a7f261 通訊錄 - 設定用戶類別及部份修正
2 years ago
bruce68410 b406125e5d 物件問題解決寫回
2 years ago
bruce68410 a7de319c42 Merge branch 'feature_231129' into dev
2 years ago
bruce68410 1acade3753 頁面功能列及確認按鈕固定置頂置底、通訊錄製作(類別設定、篩選)
2 years ago
bruce68410 35f8691a59 主頁調整、通訊錄製作
2 years ago
Wayne 15af258de7 卡片第三種版型json格式修改
2 years ago
bruce68410 c583ac9982 修正名片分享跑版問題
2 years ago
bruce68410 5f134c034b css修改
2 years ago
bruce68410 6c0d12d328 Merge remote-tracking branch 'origin/feature_231122' into feature_231122
2 years ago
bruce68410 6c7f503e8c hook使用方式修正、api串接更改
2 years ago
Wayne 8a4ac9e844 將watch移出onMounted
2 years ago
bruce68410 e7a0d071ce 修改send頁面 > 以pinia方式處理、新增名片廣告及判斷
2 years ago
DESKTOP-8UQ1PPR\09158 d07a8c2f8d 頁面修改、api串接
3 years ago
DESKTOP-8UQ1PPR\09158 c8c4d6e1c5 Merge branch 'feature_231120' into dev
3 years ago
bruce68410 2a958df547 附加廣告功能測試
3 years ago
Wayne 58b5b000a5 修改getUserData API - 2
3 years ago
Wayne a7bd5998f3 修改getUserData API
3 years ago
DESKTOP-8UQ1PPR\09158 d408a5dc4e 首頁選單按鈕位置調整、編輯頁顏色及文字調整
3 years ago
Wayne 908a601f7e 將商務卡片改為/card
3 years ago
Wayne 345da1f3f3 修改發送名片問題
3 years ago
Wayne 71ead16745 將發送名片的vuex換到pinia
3 years ago
Wayne 41bd11ab97 將發送名片的vuex換到pinia
3 years ago
Wayne ffea1f6c7c 將card的vuex換到pinia去
3 years ago
Wayne eeffd9d43d bug fix
3 years ago
Wayne 5ada3bf890 nfc版型修改
3 years ago
Wayne bdcac9a8d8 資料修改及社群分享
3 years ago
Wayne 920ff46f8c 修改會員資料...
3 years ago
bruce68410 52066a9338 Merge branch 'feature_231112' into dev
3 years ago
Wayne 3350e3bc11 版型選擇圖片不見
3 years ago
Wayne e4b9ea534a 修改人胍資源
3 years ago
bruce68410 9865617022 Merge branch 'dev' into feature_231112
3 years ago
bruce68410 09c3b39343 修改版型抓參數
3 years ago
Wayne ef891ae6a5 修改會員資料修改
3 years ago
bruce68410 4fa16a83ce 錯誤修正(顏色按鈕傳遞物件錯誤、文字靠右、更換圖片改置中)
3 years ago
DESKTOP-8UQ1PPR\09158 a4bcf1da53 購買、通訊錄頁面處理
3 years ago
DESKTOP-8UQ1PPR\09158 cb23096532 局部調整(會員等級判斷、form表遞交分開、首頁及商務卡按鈕位置更改、preview頁修改)
3 years ago
bruce68410 4a336ec9d5 發送頁面修改
3 years ago
Wayne 6ad9dccecf 移除.env.development
3 years ago
Wayne 6d9aeab33e 錯誤修正
3 years ago
Wayne 6ff433fb81 移除不必要的檔案
3 years ago
Wayne 7dd6c37332 移除不必要的檔案
3 years ago
Wayne 63b4258d75 移除.env.production
3 years ago
Wayne 7db52d1d35 將env.production移除
3 years ago
Wayne 86e074b5ed 商務卡片預覽
3 years ago
bruce68410 16a6ae2c6a 商務卡片ui修改
3 years ago
DESKTOP-8UQ1PPR\09158 87547750c5 修改
3 years ago
DESKTOP-8UQ1PPR\09158 d3176e17c4 商務卡片頁製作
3 years ago
bruce68410 672ca8652f 頁面製作串接api
3 years ago
bruce68410 19b067628d Merge branch 'feature_231027' into dev
3 years ago
bruce68410 7bd696f23c 補放原始檔案
3 years ago
bruce68410 d1bf76329c 註冊頁、首頁、會員編輯頁製作
3 years ago
Wayne ebe2bccd8a 改寫影片廣告及切換帶廣告開關
3 years ago
DESKTOP-8UQ1PPR\09158 d374e3c57e 會員資料頁面修改
3 years ago
Wayne 1b16d983ea code review
3 years ago
DESKTOP-8UQ1PPR\09158 6b309ed870 首頁串接
3 years ago
DESKTOP-8UQ1PPR\09158 c897b423a3 頁面調整及api串接
3 years ago
bruce68410 b0cf01c869 首頁頁面整理
3 years ago
Wayne d00a079c0a 修改readme
3 years ago
Wayne a41dbd2466 更改README
3 years ago
Wayne 4a97ec60fa 更改為vite建構
3 years ago
Wayne a8cf39e835 update package
3 years ago
Wayne c342e62c11 修改card2不能發送問題
3 years ago
bruce68410 1750234318 新增&修改會員中心-發送名片的版型,修改json資料轉換之對應程式,修正廣告頁面前後關係(z-index往前)
3 years ago
DESKTOP-8UQ1PPR\09158 3e2fcfafeb 版型修改
3 years ago
DESKTOP-8UQ1PPR\09158 ad56c70b7c 修改模板
3 years ago
Wayne 29b69d5138 加入首頁廣告彈窗
3 years ago
Wayne f1bda3fd50 change .env.development
3 years ago

@ -1,3 +0,0 @@
> 1%
last 2 versions
not dead

@ -1,15 +0,0 @@
NODE_ENV = production
VUE_ENV = development
BASE_URL = /home
VUE_APP_BASE_URL = https://utel.vip
VUE_APP_LINE_LIFF_ID = 1656907652-p38ddKzQ
VUE_APP_SEND_URL = https://liff.line.me/1656907652-VJq33Pdg
VUE_APP_API_URL = https://utel.vip/appapi/v1
VUE_APP_IMAGE_URL = https://utel.vip/storage

@ -1,13 +1,13 @@
NODE_ENV = production NODE_ENV = production
VUE_ENV = production VITE_ENV = production
VUE_APP_BASE_URL = https://utel.vip VITE_APP_BASE_URL = https://pro.utel.vip
VUE_APP_LINE_LIFF_ID = 1656969446-nQYlz77R VITE_APP_LINE_LIFF_ID = 1656969446-lO8Q477x
VUE_APP_SEND_URL = https://liff.line.me/1656969446-mg36Maav VITE_APP_SEND_URL = https://liff.line.me/1656969446-r07ayzzq
VUE_APP_API_URL = https://utel.vip/appapi/v1 VITE_APP_API_URL = /appapi/v1
VUE_APP_IMAGE_URL = https://utel.vip/storage VITE_APP_IMAGE_URL = /storage

@ -1,13 +1,13 @@
NODE_ENV = production NODE_ENV = development
VUE_ENV = stage VITE_ENV = development
VUE_APP_BASE_URL = https://utel.zltest.com.tw VITE_APP_BASE_URL = https://utel.zltest.com.tw
VUE_APP_LINE_LIFF_ID = 1656948609-xMp7dWAz VITE_APP_LINE_LIFF_ID = 1656948609-xMp7dWAz
VUE_APP_SEND_URL = https://liff.line.me/1656948609-BYr8Nynp VITE_APP_SEND_URL = https://liff.line.me/1656948609-BYr8Nynp
VUE_APP_API_URL = https://utel.zltest.com.tw/appapi/v1 VITE_APP_API_URL = https://utel.zltest.com.tw/appapi/v1
VUE_APP_IMAGE_URL = https://utel.zltest.com.tw/storage VITE_APP_IMAGE_URL = https://utel.zltest.com.tw/storage

@ -1,11 +1,11 @@
NODE_ENV = production NODEproduction_ENV = production
VUE_ENV = production VITE_ENV = production
VUE_APP_LINE_LIFF_ID = 1657184427-8bq9debn VITE_APP_LINE_LIFF_ID = 1657184427-8bq9debn
VUE_APP_SEND_URL = https://liff.line.me/1657184427-9GayRMQl VITE_APP_SEND_URL = https://liff.line.me/1657184427-9GayRMQl
VUE_APP_API_URL = https://card.u168.vip/appapi/v1 VITE_APP_API_URL = https://card.u168.vip/appapi/v1
VUE_APP_IMAGE_URL = https://card.u168.vip/storage VITE_APP_IMAGE_URL = https://card.u168.vip/storage

25
.gitignore vendored

@ -1,23 +1,26 @@
.DS_Store # Logs
node_modules logs
/dist *.log
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files # Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea .idea
.vscode .DS_Store
*.suo *.suo
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
.env.development

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}

@ -1,19 +1,20 @@
# ecard2 # Utel會員中心
## Project setup ## 安裝方式
```
npm install
```
### Compiles and hot-reloads for development ```shell
``` # yarn
npm run serve or
# npm install
``` ```
將example.env.development copy為 .env.development
### Compiles and minifies for production 修改 VITE_APP_LINE_LIFF_ID
```
npm run build ## 啟動方式
```
### Customize configuration ```shell
See [Configuration Reference](https://cli.vuejs.org/config/). # yarn dev
or
# npm run dev
```

@ -1,15 +0,0 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
"import",
{
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}
]
]
}

Binary file not shown.

@ -0,0 +1,13 @@
NODE_ENV = development
VITE_ENV = development
VITE_APP_BASE_URL = https://utel.zltest.com.tw
VITE_APP_LINE_LIFF_ID = 2000917272-PBWoXdOl
VITE_APP_SEND_URL = https://liff.line.me/2000917272-PBWoXdOl
VITE_APP_API_URL = https://utel.zltest.com.tw/appapi/v1
VITE_APP_IMAGE_URL = https://utel.zltest.com.tw/storage

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="zh_TW">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/>
<link rel="icon" href="favicon.ico" />
<link rel="stylesheet" href="/css/flex2html.css" />
<link
rel="stylesheet"
href="https://at.alicdn.com/t/font_3193091_nixfhsddmnl.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn"
crossorigin="anonymous"
/>
<title>UTel電子名片</title>
</head>
<body>
<div id="app"></div>
<script src="/js/flex2html.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF"
crossorigin="anonymous"
></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>

31561
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,48 +1,45 @@
{ {
"name": "utel", "name": "utel_h5_vite",
"version": "0.1.0",
"private": true, "private": true,
"version": "0.0.0",
"type": "module",
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "dev": "vite",
"build": "vue-cli-service build", "build": "vite build",
"build:u168": "vue-cli-service build --mode u168", "build:sta": "vite build --mode stage",
"build:dev": "vue-cli-service build --mode development", "preview": "vite preview"
"build:slash": "vue-cli-service build --mode slash",
"build:sta": "vue-cli-service build --mode stage",
"build:h888": "vue-cli-service build --mode h888"
}, },
"dependencies": { "dependencies": {
"@line/liff": "^2.18.2", "@line/liff": "^2.22.4",
"@soerenmartius/vue3-clipboard": "^0.1.2", "@soerenmartius/vue3-clipboard": "^0.1.2",
"axios": "^1.3.3", "axios": "^1.5.1",
"colorthief": "^2.3.2", "colorthief": "^2.4.0",
"core-js": "^3.6.5",
"ismobilejs": "^1.1.1", "ismobilejs": "^1.1.1",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.5",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.29.1", "moment": "^2.29.4",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0",
"pinia-plugin-persistedstate": "^3.2.0",
"pwacompat": "^2.0.17", "pwacompat": "^2.0.17",
"qrcode.vue": "^3.3.3", "qrcode.vue": "^3.4.1",
"register-service-worker": "^1.7.1", "register-service-worker": "^1.7.2",
"secure-ls": "^1.2.6", "secure-ls": "^1.2.6",
"vant": "^3.4.5", "vant": "^4.7.1",
"vue": "3.2.41", "vue": "^3.3.4",
"vue-advanced-cropper": "^2.8.1", "vue-advanced-cropper": "^2.8.8",
"vue-cropper": "^1.0.3", "vue-cropper": "^0.6.4",
"vue-router": "^4.0.0-0", "vue-router": "^4.2.5",
"vuex": "^4.0.0-0", "vuex": "^4.1.0",
"vuex-persistedstate": "^4.1.0" "vuex-persistedstate": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "~4.5.15", "@vant/auto-import-resolver": "^1.0.1",
"@vue/cli-plugin-pwa": "~4.5.15", "@vitejs/plugin-vue": "^4.2.3",
"@vue/cli-plugin-router": "~4.5.15", "less": "^4.2.0",
"@vue/cli-plugin-vuex": "~4.5.15", "terser": "^5.24.0",
"@vue/cli-service": "~4.5.15", "unplugin-vue-components": "^0.25.2",
"@vue/compiler-sfc": "3.2.41", "vite": "^4.4.5"
"babel-plugin-import": "^1.13.3",
"less": "^3.0.4",
"less-loader": "^5.0.0"
} }
} }

@ -45,9 +45,9 @@ strong {
font-weight: bold; font-weight: bold;
} }
.LySlider { .LySlider {
overflow: hidden; /* overflow: hidden;
overflow-x: scroll; overflow-x: scroll;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch; */
} }
.LySlider::-webkit-scrollbar { .LySlider::-webkit-scrollbar {
display: none; display: none;
@ -152,7 +152,7 @@ strong {
margin: 0 7px; margin: 0 7px;
} }
.LyMe .T1 { .LyMe .T1 {
border-radius: 17px; border-radius: 5px;
} }
.LyKi .T1 { .LyKi .T1 {
border-radius: 10px; border-radius: 10px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- <link rel="manifest" href="manifest.json"> -->
<!-- <meta name="apple-mobile-web-app-capable" content="yes"> -->
<!-- <meta name="apple-mobile-web-app-status-bar-style" content="black"> -->
<!-- <meta name="apple-mobile-web-app-title" content="UTel電子名片"> -->
<!-- <link rel="apple-touch-icon" href="icon-192x192.png" sizes="192x192"> -->
<link rel="stylesheet" href="./css/flex2html.css">
<link rel="stylesheet" href="https://at.alicdn.com/t/font_3193091_nixfhsddmnl.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
</head>
<body>
<noscript>
<strong>UTel電子名片</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="./js/flex2html.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pwacompat@2.0.15/pwacompat.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
<script>
var iOS = (/iP(hone|od|ad)/.test(navigator.userAgent));
if (iOS) {
var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
var iOSversion = parseInt(v[1], 10);
if (iOSversion < 13) {
document.querySelector('link[rel="manifest"]').setAttribute("rel", "no-on-ios");
}
}
</script>
</body>
</html>

@ -458,21 +458,29 @@ function button_object(json) {
switch (style) { switch (style) {
case "link": case "link":
ExBtn = "ExBtnL"; ExBtn = "ExBtnL";
if (color) {
style3 += `color:${color} !important;`;
}
break; break;
case "primary": case "primary":
ExBtn = "ExBtn1"; ExBtn = "ExBtn1";
if (color) {
style3 += `background-color:${color} !important;color:#ffffff !important;`;
}
break; break;
case "secondary": case "secondary":
ExBtn = "ExBtn2"; ExBtn = "ExBtn2";
if (color) {
style3 += `background-color:${color} !important;`;
}
break; break;
default: default:
ExBtn = "ExBtnL"; ExBtn = "ExBtnL";
// code block if (color) {
style3 += `color:${color} !important;`;
} }
// code block
} }
if (color) {
style3 += `background-color:${color} !important;`;
} }
if ( if (
@ -821,6 +829,8 @@ function bubble_struc(json) {
direction = !direction || direction == "" ? "ltr" : direction; direction = !direction || direction == "" ? "ltr" : direction;
size = upper2digit(size); size = upper2digit(size);
console.log(json);
return `<div class="lyItem Ly${size}"><div class="T1 fx${direction.toUpperCase()}" dir="${direction}"><!-- hero --><!-- header --><!-- body --><!-- footer --></div></div>`; return `<div class="lyItem Ly${size}"><div class="T1 fx${direction.toUpperCase()}" dir="${direction}"><!-- hero --><!-- header --><!-- body --><!-- footer --></div></div>`;
} }
function hero_struc(json) { function hero_struc(json) {
@ -907,7 +917,7 @@ function text_object(json) {
style2 += `margin-top:${margin};`; style2 += `margin-top:${margin};`;
exmgn = ""; exmgn = "";
} else { } else {
exmgn = margin ? "ExMgnL" + upperalldigit(margin) : ""; exmgn = margin ? "ExMgnT" + upperalldigit(margin) : "";
} }
alg = alg =

@ -10,16 +10,21 @@
</template> </template>
<script setup> <script setup>
import { getSiteConfig } from './api' // import { getSiteConfig } from './api'
import { useStore } from 'vuex' // import { useStore } from 'vuex'
const store = useStore() // const store = useStore()
// import { useUserStore } from '@/store/user'
// const userStore = useUserStore();
// userStore.getUserData();
</script> </script>
<style lang="less"> <style lang="less">
#app { #app {
margin-bottom: 40px; // margin-bottom: 40px;
} }
</style> </style>

@ -2,7 +2,7 @@ import axios from 'axios'
import store from '../store' import store from '../store'
const instance = axios.create({ const instance = axios.create({
baseURL: process.env.VUE_APP_API_URL, baseURL: import.meta.env.VITE_APP_API_URL,
timeout: 5000, timeout: 5000,
withCredentials: true withCredentials: true
}) })

@ -0,0 +1,5 @@
import ajax from "./ajax";
export const getCardData = async () =>
ajax(`/Card/getCardData`);

@ -7,10 +7,17 @@ export const login = async (params) => ajax(`/auth/login`, params, "POST");
export const bindCard = async (params) => export const bindCard = async (params) =>
ajax(`/auth/bindCard`, params, "POST"); ajax(`/auth/bindCard`, params, "POST");
export const bindUser = async (params) =>
ajax(`/auth/bindUser`, params, "POST");
export const checkLineId = async (lineid) => export const checkLineId = async (lineid) =>
ajax(`/auth/checkLineId`, { lineid }, "GET"); ajax(`/auth/checkLineId`, { lineid }, "GET");
export const getUserInfo = async () => ajax(`/user/getUserInfo`); export const getUserInfo = async () =>
ajax(`/user/getUserInfo`);
export const updateUserInfo = async (params) =>
ajax(`/user/updateUserInfo`, params, 'POST');
export const setUserLevel = async (level) => export const setUserLevel = async (level) =>
ajax(`/user/setUserLevel`, { level }, "POST"); ajax(`/user/setUserLevel`, { level }, "POST");
@ -18,6 +25,15 @@ export const setUserLevel = async (level) =>
export const setUserTpl = async (tpl) => export const setUserTpl = async (tpl) =>
ajax(`/user/setUserTpl`, { tpl }, "POST"); ajax(`/user/setUserTpl`, { tpl }, "POST");
export const toggleSendWithAD = async (type) =>
ajax(`/user/toggleSendWithAD`, { type }, "POST");
export const searchConnection = async (params) =>
ajax(`/user/searchConnection`, params, "POST");
export const setUserNfcTpl = async (tpl) =>
ajax(`/user/setUserNfcTpl`, { tpl }, "POST");
export const register = async (userInfo) => export const register = async (userInfo) =>
ajax(`/auth/register`, userInfo, "POST"); ajax(`/auth/register`, userInfo, "POST");
@ -54,3 +70,34 @@ export const delAuthUser = async (id) =>
export const getAuthList = async () => export const getAuthList = async () =>
ajax(`/user/getAuthList`); ajax(`/user/getAuthList`);
//廣告
export const getMovie = async () =>
ajax(`/ads/getMovie`);
export const getMarquee = async () =>
ajax(`/ads/getMarquee`);
export const getFlexcard = async () =>
ajax(`/ads/getFlexcard`);
//通訊錄
export const getUserFaviList = async (cate_id) =>
ajax(`/UserFavi/getUserFaviList`, { cate_id }, "GET");
export const addUserFavi = async (params) =>
ajax(`/UserFavi/addUserFavi`, params, "POST");
export const deleteUserFavi = async (id) =>
ajax(`/UserFavi/deleteUserFavi`, { id }, "GET");
export const setUserFaviCate = async (params) =>
ajax(`/UserFavi/setUserFaviCate`, params , "POST");
export const getUserCateList = async () =>
ajax(`/UserCate/getUserCateList`);
export const updateUserCate = async (params) =>
ajax(`/UserCate/updateUserCate`, params, "POST");

@ -0,0 +1,7 @@
import ajax from "./ajax";
export const getAreaList = async () =>
ajax(`/system/getAreaList`);
export const getWorkList = async () =>
ajax(`/system/getWorkList`);

@ -0,0 +1,17 @@
import ajax from "./ajax";
export const getUserData = async () =>
ajax(`/user/getUser`);
export const getUserExtra = async (uid) =>
ajax(`/user/getUserExtra`, { uid }, "GET");
export const updateUserExtra = async (params) =>
ajax(`/user/updateUserExtra`, params, "POST");
export const updateUserLink = async (params) =>
ajax(`/user/updateUserLink`, params, "POST");
export const updateUserAddon = async (params) =>
ajax(`/user/updateUserAddon`, {nfc_addon:params}, "POST");

@ -45,9 +45,9 @@ strong {
font-weight: bold; font-weight: bold;
} }
.LySlider { .LySlider {
overflow: hidden; /* overflow: hidden;
overflow-x: scroll; overflow-x: scroll;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch; */
} }
.LySlider::-webkit-scrollbar { .LySlider::-webkit-scrollbar {
display: none; display: none;

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@ -0,0 +1,883 @@
{
"version": "7",
"about": "This is a Prepros (https://prepros.io) configuration file. You can commit this file to a git repo to backup and sync project configurations.",
"config": {
"proxy": {
"enable": false,
"target": "",
"useLocalAssets": false
},
"reload": {
"enable": true,
"delay": 0,
"animate": true,
"afterUpload": false
},
"sync": {
"enable": false,
"mouse": true,
"keyboard": true,
"form": true,
"scroll": true
},
"watcher": {
"enable": true,
"maxFiles": 2000,
"usePolling": false,
"pollingInterval": 500,
"extensions": [
".html",
".htm",
".php"
],
"ignore": {
"patterns": [
".*",
"wp-admin",
"wp-includes",
"node_modules",
"Prepros Export",
"bower_components"
],
"exceptions": []
}
},
"exporter": {
"ignore": {
"patterns": [
".*",
"desktop.ini",
"prepros.cfg",
"node_modules",
"Prepros Export",
"prepros.config",
"prepros-6.config",
"*-original.jpg",
"*-original.jpeg",
"*-original.png",
"*-original.svg",
"*.scss",
"*.sass",
"*.less",
"*.pug",
"*.jade",
"*.styl",
"*.haml",
"*.slim",
"*.coffee",
"*.kit",
"*.turf",
"*.ts"
],
"exceptions": []
}
},
"uploader": {
"remotePath": "",
"timeout": 20000,
"autoUpload": false,
"reuseConnection": true,
"connectionType": "ftp",
"exportHistory": true,
"history": []
},
"packages": {
"createPackageLock": true
},
"images": {
"preserveOriginal": true
},
"tasks": {
"autoprefixer": {
"cascade": true,
"add": true,
"remove": true,
"supports": true,
"flexbox": true,
"grid": "autoplace",
"browsers": [
"last 2 versions"
],
"sourceMap": false
},
"babel": {
"sourceMap": false,
"presets": {
"@babel/preset-env": {
"enable": true,
"options": {
"targets": [
"last 2 versions"
],
"preserveImports": false,
"polyfills": false
}
},
"@babel/preset-react": true,
"@babel/preset-flow": false
},
"plugins": {
"@babel/plugin-proposal-class-static-block": false,
"@babel/plugin-proposal-class-properties": false,
"@babel/plugin-proposal-decorators": {
"enable": false,
"options": {
"decoratorsBeforeExport": true
}
},
"@babel/plugin-proposal-export-namespace-from": false,
"@babel/plugin-proposal-function-sent": false,
"@babel/plugin-proposal-logical-assignment-operators": false,
"@babel/plugin-proposal-nullish-coalescing-operator": false,
"@babel/plugin-proposal-numeric-separator": false,
"@babel/plugin-proposal-optional-chaining": false,
"@babel/plugin-proposal-private-methods": false,
"@babel/plugin-proposal-throw-expressions": false
},
"customPresets": [],
"customPlugins": []
},
"bundle-js": {
"sourceMap": false,
"exclude": [
"node_modules",
"bower_components"
],
"devMode": true,
"globals": [],
"externals": [],
"babel": {
"enable": true,
"options": {
"sourceMap": false,
"presets": {
"@babel/preset-env": {
"enable": true,
"options": {
"targets": [
"last 2 versions"
],
"preserveImports": false,
"polyfills": false
}
},
"@babel/preset-react": true,
"@babel/preset-flow": false
},
"plugins": {
"@babel/plugin-proposal-class-static-block": false,
"@babel/plugin-proposal-class-properties": false,
"@babel/plugin-proposal-decorators": {
"enable": false,
"options": {
"decoratorsBeforeExport": true
}
},
"@babel/plugin-proposal-export-namespace-from": false,
"@babel/plugin-proposal-function-sent": false,
"@babel/plugin-proposal-logical-assignment-operators": false,
"@babel/plugin-proposal-nullish-coalescing-operator": false,
"@babel/plugin-proposal-numeric-separator": false,
"@babel/plugin-proposal-optional-chaining": false,
"@babel/plugin-proposal-private-methods": false,
"@babel/plugin-proposal-throw-expressions": false
},
"customPresets": [],
"customPlugins": []
}
},
"css": {
"enable": true
}
},
"coffeescript": {
"header": false,
"bare": false,
"sourceMap": false
},
"command": {
"command": "",
"rootDir": ""
},
"concat-js": {
"sourceMap": false,
"rootDir": ""
},
"copy": {
"sourceMap": false
},
"dart-sass": {
"indentType": "space",
"allowWildcardImports": false,
"indentWidth": 2,
"linefeed": "lf",
"removeCharset": false,
"sourceMap": false
},
"haml": {
"doubleQuoteAttributes": true
},
"jpg": {
"quality": 90
},
"less": {
"javascriptEnabled": false,
"strictImports": false,
"insecure": false,
"math": "always",
"strictUnits": false,
"dumpLineNumbers": false,
"sourceMap": false
},
"markdown": {
"githubFlavored": true,
"wrapWithHtml": false
},
"minify-css": {
"sourceMap": false
},
"minify-html": {
"caseSensitive": false,
"collapseBooleanAttributes": true,
"collapseInlineTagWhitespace": false,
"collapseWhitespace": true,
"conservativeCollapse": false,
"decodeEntities": false,
"html5": true,
"includeAutoGeneratedTags": true,
"keepClosingSlash": false,
"minifyCSS": true,
"minifyJS": true,
"preserveLineBreaks": false,
"preventAttributesEscaping": false,
"processConditionalComments": false,
"removeAttributeQuotes": false,
"removeComments": true,
"removeEmptyAttributes": false,
"removeEmptyElement": false,
"removeOptionalTags": false,
"removeRedundantAttributes": false,
"removeScriptTypeAttributes": false,
"removeStyleLinkTypeAttributes": false,
"removeTagWhitespace": false,
"sortAttributes": false,
"sortClassName": false,
"useShortDoctype": true
},
"minify-js": {
"parse": {
"bare_returns": false
},
"compress": {
"arrows": true,
"arguments": false,
"booleans": true,
"booleans_as_integers": false,
"collapse_vars": true,
"comparisons": true,
"computed_props": true,
"conditionals": true,
"dead_code": true,
"directives": true,
"drop_console": false,
"drop_debugger": true,
"evaluate": true,
"expression": false,
"global_defs": [],
"hoist_funs": false,
"hoist_props": true,
"hoist_vars": false,
"if_return": true,
"inline": 3,
"join_vars": true,
"keep_fargs": true,
"keep_infinity": false,
"loops": true,
"negate_iife": true,
"properties": true,
"pure_funcs": [],
"pure_getters": false,
"reduce_funcs": true,
"reduce_vars": true,
"sequences": true,
"side_effects": true,
"switches": true,
"top_retain": [],
"typeofs": true,
"unsafe": false,
"unsafe_arrows": false,
"unsafe_comps": false,
"unsafe_Function": false,
"unsafe_math": false,
"unsafe_proto": false,
"unsafe_regexp": false,
"unsafe_undefined": false,
"unused": true
},
"mangle": {
"eval": false,
"reserved": []
},
"output": {
"ascii_only": false,
"braces": false,
"comments": "none",
"inline_script": true,
"keep_numbers": false,
"keep_quoted_props": false,
"preamble": null,
"quote_keys": false,
"quote_style": 0,
"semicolons": true,
"shebang": true,
"webkit": false,
"wrap_iife": false,
"wrap_func_args": true
},
"sourceMap": false,
"toplevel": false,
"ie8": false,
"keep_classnames": false,
"keep_fnames": false,
"safari10": false
},
"node-sass": {
"indentType": "space",
"allowWildcardImports": false,
"indentWidth": 2,
"linefeed": "lf",
"outputStyle": "expanded",
"precision": 10,
"sourceMap": false,
"removeCharset": false,
"sourceComments": false
},
"png": {
"quality": 90
},
"postcss-import": {
"ignoreKeywords": [],
"sourceMap": false
},
"postcss-preset-env": {
"stage": 2,
"browsers": [
"last 2 versions"
],
"sourceMap": false
},
"pug": {
"pretty": true
},
"slim": {
"indent": "space",
"indentSize": 2,
"pretty": true
},
"stylus": {
"useNib": true,
"sourceMap": false,
"linenos": false
},
"svg": {
"cleanupAttrs": true,
"removeDoctype": true,
"removeXMLProcInst": true,
"removeComments": true,
"removeMetadata": true,
"removeTitle": true,
"removeDesc": true,
"removeUselessDefs": true,
"removeEditorsNSData": true,
"removeEmptyAttrs": true,
"removeHiddenElems": true,
"removeEmptyText": true,
"removeEmptyContainers": true,
"removeViewBox": false,
"cleanupEnableBackground": true,
"convertStyleToAttrs": true,
"convertColors": true,
"convertPathData": true,
"convertTransform": true,
"removeUnknownsAndDefaults": true,
"removeNonInheritableGroupAttrs": true,
"removeUselessStrokeAndFill": true,
"removeUnusedNS": true,
"cleanupIDs": true,
"cleanupNumericValues": true,
"moveElemsAttrsToGroup": true,
"moveGroupAttrsToElems": true,
"collapseGroups": true,
"removeRasterImages": false,
"mergePaths": true,
"convertShapeToPath": true,
"sortAttrs": true,
"removeDimensions": true
},
"tailwindcss": {
"rootDir": "",
"content": [
"**/*.html",
"**/*.htm",
"**/*.php",
"**/*.js",
"!wp-admin",
"!wp-includes",
"!node_modules",
"!Prepros Export"
]
},
"turf": {
"rootDir": ""
}
},
"fileTypes": {
"sass": {
"extensions": [
".scss",
".sass"
],
"autoCompile": true,
"sourceMap": false,
"tasks": [
{
"task": "dart-sass",
"enable": true
},
{
"task": "autoprefixer",
"enable": true
},
{
"task": "minify-css",
"enable": false
}
],
"output": {
"extension": ".css",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "scss",
"replaceWith": "css"
},
{
"segment": "sass",
"replaceWith": "css"
}
]
}
},
"less": {
"extensions": [
".less"
],
"autoCompile": true,
"sourceMap": false,
"tasks": [
{
"task": "less",
"enable": true
},
{
"task": "autoprefixer",
"enable": true
},
{
"task": "minify-css",
"enable": false
}
],
"output": {
"extension": ".css",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "less",
"replaceWith": "css"
}
]
}
},
"pug": {
"extensions": [
".pug",
".jade"
],
"autoCompile": true,
"tasks": [
{
"task": "pug",
"enable": true
},
{
"task": "minify-html",
"enable": false
}
],
"output": {
"extension": ".html",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "pug",
"replaceWith": "html"
}
]
}
},
"css": {
"extensions": [
".css"
],
"autoCompile": false,
"sourceMap": false,
"tasks": [
{
"task": "copy",
"enable": true
},
{
"task": "tailwindcss",
"enable": false
},
{
"task": "postcss-import",
"enable": false
},
{
"task": "postcss-preset-env",
"enable": false
},
{
"task": "autoprefixer",
"enable": true
},
{
"task": "minify-css",
"enable": true
}
],
"output": {
"extension": ".css",
"type": "SOURCE_RELATIVE",
"relativePath": "",
"suffix": "-dist",
"alwaysSuffix": false
}
},
"javascript": {
"extensions": [
".js",
".jsx"
],
"autoCompile": false,
"sourceMap": false,
"tasks": [
{
"task": "copy",
"enable": true
},
{
"task": "concat-js",
"enable": false
},
{
"task": "babel",
"enable": false
},
{
"task": "bundle-js",
"enable": false
},
{
"task": "minify-js",
"enable": true
}
],
"output": {
"extension": ".js",
"type": "SOURCE_RELATIVE",
"relativePath": "",
"suffix": "-dist",
"alwaysSuffix": false
}
},
"stylus": {
"extensions": [
".styl"
],
"autoCompile": true,
"sourceMap": false,
"tasks": [
{
"task": "stylus",
"enable": true
},
{
"task": "autoprefixer",
"enable": true
},
{
"task": "minify-css",
"enable": false
}
],
"output": {
"extension": ".css",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "stylus",
"replaceWith": "css"
},
{
"segment": "styl",
"replaceWith": "css"
}
]
}
},
"markdown": {
"extensions": [
".md",
".markdown",
".mkd"
],
"autoCompile": false,
"tasks": [
{
"task": "markdown",
"enable": true
},
{
"task": "minify-html",
"enable": false
}
],
"output": {
"extension": ".html",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "markdown",
"replaceWith": "html"
}
]
}
},
"haml": {
"extensions": [
".haml"
],
"autoCompile": true,
"tasks": [
{
"task": "haml",
"enable": true
},
{
"task": "minify-html",
"enable": false
}
],
"output": {
"extension": ".html",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "haml",
"replaceWith": "html"
}
]
}
},
"slim": {
"extensions": [
".slim"
],
"autoCompile": true,
"tasks": [
{
"task": "slim",
"enable": true
},
{
"task": "minify-html",
"enable": false
}
],
"output": {
"extension": ".html",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "slim",
"replaceWith": "html"
}
]
}
},
"coffeescript": {
"extensions": [
".coffee"
],
"autoCompile": true,
"sourceMap": false,
"tasks": [
{
"task": "coffeescript",
"enable": true
},
{
"task": "babel",
"enable": false
},
{
"task": "bundle-js",
"enable": false
},
{
"task": "minify-js",
"enable": false
}
],
"output": {
"extension": ".js",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "coffee-script",
"replaceWith": "js"
},
{
"segment": "coffeescript",
"replaceWith": "js"
},
{
"segment": "coffee",
"replaceWith": "js"
}
]
}
},
"turf": {
"extensions": [
".turf",
".kit"
],
"autoCompile": true,
"tasks": [
{
"task": "turf",
"enable": true
},
{
"task": "minify-html",
"enable": false
}
],
"output": {
"extension": ".html",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "turf",
"replaceWith": "html"
}
]
}
},
"typescript": {
"extensions": [
".ts",
".tsx"
],
"autoCompile": true,
"sourceMap": false,
"tasks": [
{
"task": "copy",
"enable": true
},
{
"task": "babel",
"enable": true
},
{
"task": "bundle-js",
"enable": false
},
{
"task": "minify-js",
"enable": false
}
],
"output": {
"extension": ".js",
"type": "REPLACE_SEGMENTS",
"segments": [
{
"segment": "typescript",
"replaceWith": "js"
},
{
"segment": "ts",
"replaceWith": "js"
}
]
}
},
"jpg": {
"extensions": [
".jpg",
".jpeg"
],
"tasks": [
{
"task": "jpg",
"enable": true
}
],
"output": {
"extension": ".jpg",
"type": "SOURCE_RELATIVE",
"relativePath": ""
}
},
"png": {
"extensions": [
".png"
],
"tasks": [
{
"task": "png",
"enable": true
}
],
"output": {
"extension": ".png",
"type": "SOURCE_RELATIVE",
"relativePath": ""
}
},
"svg": {
"extensions": [
".svg"
],
"tasks": [
{
"task": "svg",
"enable": true
}
],
"output": {
"extension": ".svg",
"type": "SOURCE_RELATIVE",
"relativePath": ""
}
}
},
"files": []
}
}

@ -0,0 +1,113 @@
//===
$heightObj: (
basic: 45px
);
//===
$gutter: (
basic: 20px,
double: 40px
);
//
$radius: (
basic: 3px
);
//
$basicColor: (
lightBlue:#b2c4ce,
skyBlue:#5b7b94,
moBlue:#4a677d,
darkBlue:#345068,
lightPink:#f1e6e2,
cherry:#E31D64,
mintGreen:#f2f8e7,
limeGreen:#94ac5e,
tomatoRed:#f85d5d,
earthGold:#BC9F75,
silver:#eeeeee,
gray:#b1b3b6
);
$textArr:
(lightBlue, map-get($basicColor, lightBlue)),
(skyBlue, map-get($basicColor, skyBlue)),
(moBlue, map-get($basicColor, moBlue)),
(darkBlue, map-get($basicColor, darkBlue)),
(lightPink, map-get($basicColor, lightPink)),
(cherry, map-get($basicColor, cherry)),
(mintGreen, map-get($basicColor, mintGreen)),
(limeGreen, map-get($basicColor, limeGreen)),
(tomatoRed, map-get($basicColor, tomatoRed)),
(earthGold, map-get($basicColor, earthGold)),
(silver, map-get($basicColor, silver)),
(gray, map-get($basicColor, gray)),
;
//button
@each $class, $color in $textArr {
.text-#{"" + $class} {
color: $color !important;
}
.bg-#{"" + $class} {
background-color: $color !important;
}
.bd-#{"" + $class} {
border-style: solid;
border-color: $color !important;
}
}
//======extand
%centerFlex {
display: flex;
justify-content: center;
align-items: center;
}
%bwtFlex {
display: flex;
justify-content: space-between;
align-items: center;
}
%posCenter {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
%resetForm {
appearance: none;
}
%clearFix {
&:after {
content: '';
display: block;
clear: both;
}
}
//========mixin
@mixin size($w, $h:$w) {
width: $w;
height: $h;
}
@mixin basicSize($w, $h) {
min-width: $w;
min-height: $h;
}
//margin padding
@mixin elGutter($key, $value) {
#{$key}: $value;
&:last-child {
#{$key}: 0;
}
}

@ -0,0 +1,138 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&family=Raleway:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
*:before,
*:after {
box-sizing: border-box;
}
body {
font-family: 'Noto Sans TC', "微軟正黑體", "Microsoft JhengHei", sans-serif;
font-size: 14px;
line-height: 1.5;
margin: 0;
padding: 0;
color: #666;
background-color: #ffffff;
}
ol, ul {
list-style: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
a,
span {
display: inline-block;
}
button,a{
border-width: 1px;
outline: none !important;
cursor: pointer;
&:focus {
outline: none;
box-shadow: none !important;
}
}
a,
a:hover,
a:focus {
color: #37455E;
text-decoration: none;
outline: none;
}
ul{
margin:0;
padding:0;
padding-left: 20px;
li{
list-style:none;
}
}
textarea{
min-height: 200px;
}
hr{
margin: 15px 0;
&.dashed{
border-style: dashed;
margin: 25px 0;
}
}
.left {
float: left;
}
.rel {
position: relative;
}
.ellipsis{
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-wrap: break-word;
&.e2{-webkit-line-clamp: 2;}
&.e3{-webkit-line-clamp: 3;}
&.e4{-webkit-line-clamp: 4;}
&.e5{-webkit-line-clamp: 5;}
&.e6{-webkit-line-clamp: 6;}
}
.centerFlex {
display: flex;
justify-content: center;
align-items: center;
}
.bwtFlex {
display: flex;
justify-content: space-between;
align-items: center;
}
h1,h2,h3,h4,h5,h6{margin:0;}
// h2{font-size: 4rem;}
// h3{font-size: 3.4rem;line-height: 0.9em;}
// h4{font-size: 2.2rem;}
// h5{font-size: 1.8rem;}
// h6{font-size: 1.4rem;}

@ -0,0 +1,53 @@
$normalArr:
(lightBlue, #fff, map-get($basicColor, lightBlue), map-get($basicColor, lightBlue)),
(skyBlue, #fff, map-get($basicColor, skyBlue), map-get($basicColor, skyBlue)),
(moBlue, #fff, map-get($basicColor, moBlue), map-get($basicColor, moBlue)),
(darkBlue, #fff, map-get($basicColor, darkBlue), map-get($basicColor, darkBlue)),
(lightPink, #fff, map-get($basicColor, lightPink), map-get($basicColor, lightPink)),
(cherry, #fff, map-get($basicColor, cherry), map-get($basicColor, cherry)),
(limeGreen, #fff, map-get($basicColor, limeGreen), map-get($basicColor, limeGreen)),
(tomatoRed, #fff, map-get($basicColor, tomatoRed), map-get($basicColor, tomatoRed)),
(earthGold, #fff, map-get($basicColor, earthGold), map-get($basicColor, earthGold)),
;
$outlineArr:
(lightBlue, 1px, map-get($basicColor, lightBlue), transparent, map-get($basicColor, lightBlue)),
(skyBlue, 1px, map-get($basicColor, skyBlue), transparent, map-get($basicColor, skyBlue)),
(moBlue, 1px, map-get($basicColor, moBlue), transparent, map-get($basicColor, moBlue)),
(darkBlue, 1px, map-get($basicColor, darkBlue), transparent, map-get($basicColor, darkBlue)),
(lightPink, 1px, map-get($basicColor, lightPink), transparent, map-get($basicColor, lightPink)),
(cherry, 1px, map-get($basicColor, cherry), transparent, map-get($basicColor, cherry)),
(limeGreen, 1px, map-get($basicColor, limeGreen), transparent, map-get($basicColor, limeGreen)),
(tomatoRed, 1px, map-get($basicColor, tomatoRed), transparent, map-get($basicColor, tomatoRed)),
(earthGold, 1px, map-get($basicColor, earthGold), transparent, map-get($basicColor, earthGold)),
;
//button
@each $class, $color, $bgColor, $border in $normalArr {
.btn-#{"" + $class} {
@include normalBtn($color, $bgColor, $border);
}
}
//
@each $class, $bdWidth, $color, $bgColor, $bdColor in $outlineArr {
.btn-outline-#{"" + $class} {
@include outlineBtn($bdWidth, $color, $bgColor, $bdColor);
background-color: #fff;
}
}
.btn-outline-limeGreen {
&.active {
color: #fff;
background-color: #b4d26c;
}
&.disabled {
cursor: not-allowed;
&:hover {
background-color: #fff;
color: #b4d26c;
}
}
}

@ -0,0 +1,35 @@
%button {
border-radius: map-get($radius, basic);
&.limit{
width:200px;
}
}
//button
@mixin normalBtn($color, $bgColor, $bdColor) {
@extend %button;
@if $bdColor == none {
border: none;
} @else {
border: 1px solid $bdColor !important;
}
color: $color;
background-color: $bgColor;
&:hover{
color:#fff;
background-color: darken($bgColor, 10%);
}
}
// button
@mixin outlineBtn($bdWidth, $color, $bgColor, $bdColor) {
@extend %button;
border: $bdWidth solid $bdColor;
color: $color;
background-color: $bgColor;
&:hover{
color:#fff;
background-color: $color;
}
}

@ -0,0 +1,178 @@
[v-cloak] {
display: none;
}
/* ========================================= vant ============================================= */
.van-nav-bar{
position: sticky;
top:0;
z-index: 998;
}
.van-notice-bar{
position: sticky;
top:78px;
font-size: 18px;
z-index: 997;
}
.van-popup{
&.van-toast{
display: flex;
justify-content: center;
align-items: center;
padding: 30px;
}
&.cropPopup{
display: block;
max-width: 400px;
width: 90%;
height: 430px;
top: 30%;
margin: auto;
padding: 0;
}
}
.van-tabs{
padding:20px 0 0px;
.van-tabs__wrap{
height:initial !important;
.van-tabs__nav{
padding:0;
background-color: transparent;
.van-tab{
&.van-tab--active{
.tab_item{
color: #345068;
}
}
.tab_item{
display: flex;
align-items: center;
flex-direction: column;
color: #5b7b94;
}
}
.van-tabs__line{
bottom:0;
background: #345068;
}
}
}
}
.van-cell-group{
border-radius: 5px;
margin-bottom: 15px;
overflow: hidden;
.van-cell{
padding: 6px 16px;
align-items: center;
&::after{
border-bottom:1px #e3e3e3 solid;
transform: none;
}
&.longText{
.van-field__label{
width:160px;
}
}
.van-field__label{
position: relative;
display: flex;
padding: 4px 0;
font-weight: bold;
&:before{
position: absolute;
left:-8px;
}
i,svg{
color: #5b7b94;
margin-top: 5px;
margin-right: 5px;
}
}
.van-cell{
padding: 6px 0px;
}
}
}
/* ========================================= stage ============================================= */
.page{
min-height:100vh;
background-color: #f1e6e2 ;
}
.content{
padding: 15px 0;
background-color: #b2c4ce;
}
.upload-main{
display: flex;
justify-content: center;
align-items: center;
.upload-img{
border:1px #d8d8d8 solid;
&.avatar{
width: 100px;
aspect-ratio: 1/1;
border-radius: 50%;
}
}
}
.cropper {
height: 300px;
background: #DDD;
}
.cropper-section{
margin: 0 auto;
position: fixed;
text-align: center;
top: 60px;
width: 100%;
max-width: 500px;
z-index: 8888;
.crop-area{
margin: 5 auto;
width: 100%;
}
.crop-btn{
background-color: #666;
text-align: center;
}
}
/* ========================================= other ============================================= */
.imgCnt{
position: relative;
overflow: hidden;
img{
width:100%;
height:100%;
object-fit: cover;
}
}
.bottomBtnCnt{
padding: 15px;
background: linear-gradient(to top,#b2c4ce 0%,#b2c4ce 80%,rgba(178,196,206,.5) 90%,rgba(178,196,206,0) 100%);
}

@ -0,0 +1,17 @@
.header{
position: relative;
width:100%;
text-align: center;
padding: 15px 0;
background-color: #345068;
.uname {
color: #fff;
margin-bottom: 5px;
font-weight: bold;
}
.umoney {
color: #fff;
opacity: .6;
}
}

@ -0,0 +1,18 @@
// @import './bootstrap/bootstrap';
@import './base/global';
@import './base/reset';
@import './components/button';
@import './components/btn';
@import './layout/navbar';
@import './layout/layout';
@import './venders/vender';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,6 @@
@import './font-awesome.min.scss';
// @import './lightgallery.scss';
// @import './slick.scss';
// @import './slick-theme.scss';
@import './swiper.scss';
// @import './animate.min.scss';

@ -37,7 +37,7 @@
<script> <script>
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { Toast } from 'vant'; import { showToast } from 'vant';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
@ -52,7 +52,7 @@ export default {
const showShareQrcode = ref(false) const showShareQrcode = ref(false)
const imageUrl = ref(process.env.VUE_APP_IMAGE_URL) const imageUrl = ref(import.meta.env.VITE_APP_IMAGE_URL)
const options = [ const options = [
{ name: '二维码', icon: 'qrcode', key: 'qrcode' }, { name: '二维码', icon: 'qrcode', key: 'qrcode' },
@ -63,8 +63,8 @@ export default {
if (option.key === 'qrcode') { if (option.key === 'qrcode') {
showShareQrcode.value = true showShareQrcode.value = true
} else if (option.key === 'link') { } else if (option.key === 'link') {
toClipboard(`https://liff.line.me/${process.env.VUE_APP_LINE_LIFF_ID}/?aid=${store.state.user.userInfo.agent_prefix}`) toClipboard(`https://liff.line.me/${import.meta.env.VITE_APP_LINE_LIFF_ID}/?aid=${store.state.user.userInfo.agent_prefix}`)
Toast('已放入剪貼簿') showToast('已放入剪貼簿')
} }
showShare.value = false showShare.value = false
}; };
@ -149,39 +149,39 @@ export default {
} }
.footerMenu ul li a em.home { .footerMenu ul li a em.home {
background-image: url(~@/assets/images/f01-1.png); background-image: url(@/assets/images/f01-1.png);
} }
.footerMenu ul li a.active em.home { .footerMenu ul li a.active em.home {
background-image: url(~@/assets/images/f01-2.png); background-image: url(@/assets/images/f01-2.png);
} }
.footerMenu ul li a em.my { .footerMenu ul li a em.my {
background-image: url(~@/assets/images/f02-1.png); background-image: url(@/assets/images/f02-1.png);
} }
.footerMenu ul li a.active em.my { .footerMenu ul li a.active em.my {
background-image: url(~@/assets/images/f02-2.png); background-image: url(@/assets/images/f02-2.png);
} }
.footerMenu ul li a em.back { .footerMenu ul li a em.back {
background-image: url(~@/assets/images/f04.png); background-image: url(@/assets/images/f04.png);
} }
.footerMenu ul li a em.act { .footerMenu ul li a em.act {
background-image: url(~@/assets/images/f05-1.png); background-image: url(@/assets/images/f05-1.png);
} }
.footerMenu ul li a.active em.act { .footerMenu ul li a.active em.act {
background-image: url(~@/assets/images/f05-2.png); background-image: url(@/assets/images/f05-2.png);
} }
.footerMenu ul li a em.buy { .footerMenu ul li a em.buy {
background-image: url(~@/assets/images/f06-1.png); background-image: url(@/assets/images/f06-1.png);
} }
.footerMenu ul li a.active em.buy { .footerMenu ul li a.active em.buy {
background-image: url(~@/assets/images/f06-2.png); background-image: url(@/assets/images/f06-2.png);
} }
.footerMenu ul li a p { .footerMenu ul li a p {

@ -1,5 +1,22 @@
<template> <template>
<van-nav-bar title="預覽:)" right-text="" @click-right="$router.back()" /> <div class="preview page">
<van-nav-bar
class="bg-skyBlue py-1"
@click-left="$router.push('/card')"
>
<template #title>
<h5 class="text-white mb-1"><strong>預覽</strong></h5>
</template>
<template #left>
<h4>
<i
class="fa-solid fa-angle-left text-white"
:style="{ opacity: 0.5 }"
></i>
</h4>
</template>
</van-nav-bar>
<div class="flex-section"> <div class="flex-section">
<div class="table-responsive"> <div class="table-responsive">
<div class="chatbox"> <div class="chatbox">
@ -7,6 +24,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup> <script setup>
@ -21,7 +39,7 @@ const flexRef = ref(null)
onActivated(() => { onActivated(() => {
flexRef.value.innerHTML = '' flexRef.value.innerHTML = ''
let flexContent = genCard1(JSON.parse(route.params.content)) let flexContent = genCard1(JSON.parse(history.state.content))
flex2html("flex", flexContent) flex2html("flex", flexContent)
}) })
@ -34,12 +52,12 @@ onDeactivated(() => {
.flex-section { .flex-section {
// color: white; // color: white;
// z-index: 99999; // z-index: 99999;
background-color: #666; background-color: #333;
} }
.chatbox { .chatbox {
background-color: #666; background-color: #000;
margin-top: 10px; margin-top: 10px;
padding-top: 10px; padding-top: 10px;
} }

@ -2,16 +2,32 @@ import { createApp } from "vue";
import App from "./App.vue"; import App from "./App.vue";
import router from "./router"; import router from "./router";
import store from "./store"; import store from "./store";
import pinia from './store/pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
// import { initStore } from './utils/initStore';
import { vant } from "@/plugins/vant"; import liff from '@line/liff';
import { VueClipboard } from "@soerenmartius/vue3-clipboard"; import { VueClipboard } from "@soerenmartius/vue3-clipboard";
import "@/assets/css/normalize.css"; // import "@/assets/css/normalize.css";
import "@/assets/css/common.less"; import "@/assets/css/common.less";
// import './registerServiceWorker' // import './registerServiceWorker'
const vue = createApp(App); liff.init({
liffId: import.meta.env.VITE_APP_LINE_LIFF_ID
}).then(() => {
window.liff = liff;
vant(vue); const vue = createApp(App);
pinia.use(piniaPluginPersistedstate);
// 將LIFF實例提供給應用
vue.use(VueClipboard); vue.use(VueClipboard);
vue.use(pinia);
// 初始化Store
vue.use(store).use(router).mount("#app"); vue.use(store).use(router).mount("#app");
}).catch((error) => {
console.error('初始化 LIFF 時出錯:', error);
});

@ -1,7 +1,7 @@
import { import {
Locale, Locale,
Button, Button,
Toast, showToast,
ShareSheet, ShareSheet,
NavBar, NavBar,
Tab, Tab,

@ -2,8 +2,8 @@
import { register } from 'register-service-worker' import { register } from 'register-service-worker'
// if (process.env.NODE_ENV === 'production') { // if (import.meta.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, { register(`${import.meta.env.BASE_URL}service-worker.js`, {
ready () { ready () {
console.log( console.log(
'App is being served from cache by a service worker.\n' + 'App is being served from cache by a service worker.\n' +

@ -19,25 +19,31 @@ const routes = [
path: "/send", path: "/send",
name: "Send", name: "Send",
component: () => component: () =>
import(/* webpackChunkName: "send" */ "../views/Send/index.vue"), import("../views/Send/index.vue"),
}, },
{ {
path: "/shop", path: "/shop",
name: "Shop", name: "Shop",
component: () => component: () =>
import(/* webpackChunkName: "shop" */ "../views/Shop/index.vue"), import("../views/Shop/index.vue"),
}, },
{ {
path: "/shop/inputsn", path: "/shop/inputsn",
name: "InputSN", name: "InputSN",
component: () => component: () =>
import(/* webpackChunkName: "user" */ "../views/Shop/Inputsn.vue"), import("../views/Shop/Inputsn.vue"),
}, },
{ {
path: "/member", path: "/member",
name: "Member", name: "Member",
component: () => component: () =>
import(/* webpackChunkName: "user" */ "../views/Member/index.vue"), import("../views/Member/index.vue"),
},
{
path: "/address",
name: "Address",
component: () =>
import("../views/Address/index.vue"),
}, },
{ {
path: "/card", path: "/card",
@ -45,30 +51,30 @@ const routes = [
component: Card, component: Card,
children: [ children: [
{ {
path: "/card/edit", path: "/card",
name: "CardEdit", name: "CardEdit",
component: () => component: () =>
import(/* webpackChunkName: "card" */ "../views/Card/Edit"), import("../views/Card/Edit.vue"),
meta: { keepAlive: true }, meta: { keepAlive: true },
}, },
{ {
path: "/card/notice", path: "/card/notice",
name: "CardNotice", name: "CardNotice",
component: () => component: () =>
import(/* webpackChunkName: "card" */ "../views/Card/Notice"), import("../views/Card/Notice.vue"),
}, },
{ {
path: "/card/video", path: "/card/video",
name: "CardVideo", name: "CardVideo",
component: () => component: () =>
import(/* webpackChunkName: "card" */ "../views/Card/Video"), import("../views/Card/Video.vue"),
meta: { keepAlive: true }, meta: { keepAlive: true },
}, },
{ {
path: "/card/preview", path: "/card/preview",
name: "CardPreview", name: "CardPreview",
component: () => component: () =>
import(/* webpackChunkName: "card" */ "@/components/Preview"), import("@/components/Preview.vue"),
meta: { keepAlive: true }, meta: { keepAlive: true },
}, },
], ],
@ -99,7 +105,7 @@ const routes = [
path: "/auth/preview", path: "/auth/preview",
name: "AuthPreview", name: "AuthPreview",
component: () => component: () =>
import(/* webpackChunkName: "card" */ "@/components/Preview"), import("@/components/Preview.vue"),
meta: { keepAlive: true }, meta: { keepAlive: true },
}, },
], ],
@ -108,33 +114,40 @@ const routes = [
path: "/register", path: "/register",
name: "Register", name: "Register",
component: () => component: () =>
import(/* webpackChunkName: "auth" */ "../views/Register/index.vue"), import("../views/Register/index.vue"),
// component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') // component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}, },
{ {
path: "/login", path: "/login",
name: "Login", name: "Login",
component: () => component: () =>
import(/* webpackChunkName: "auth" */ "../views/Login/index.vue"), import("../views/Login/index.vue"),
},
{
path: "/actlogin",
name: "ActLogin",
component: () =>
import("../views/Login/actLogin.vue"),
}, },
{ {
path: "/test", path: "/test",
name: "Test", name: "Test",
component: () => import(/* webpackChunkName: "auth" */ "../views/Test.vue"), component: () => import("../views/Test.vue"),
}, },
]; ];
const router = createRouter({ const router = createRouter({
history: createWebHistory(process.env.BASE_URL), history: createWebHistory('/home'),
routes, routes,
}); });
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start(); NProgress.start();
if (to.path !== "/" && to.path !== "/login" && to.path !== "/register") { if (to.path !== "/" && to.path !== "/login" && to.path !== "/actlogin" && to.path !== "/register") {
if (!sessionStorage.getItem("token")) { if (!sessionStorage.getItem("token")) {
next("/"); sessionStorage.setItem("redirect", to.fullPath);
return next("/actlogin");
} }
// if(!store.state.user.userInfo){ // if(!store.state.user.userInfo){
@ -142,7 +155,7 @@ router.beforeEach((to, from, next) => {
// } // }
} }
next(); return next();
}); });
router.afterEach(() => { router.afterEach(() => {

@ -0,0 +1,41 @@
import { defineStore } from 'pinia'
import { updateCusCard } from "@/api";
import { getCardData } from "@/api/card";
export const useCardStore = defineStore('card', {
state: () => {
return {
cusCard: {
card_title: '',
show_cus: 1,
cus_card: '',
},
vipCard: [],
}
},
getters: {
},
actions: {
async getCardData() {
let res = await getCardData();
if (res.code === 200) {
this.cusCard = res.data.cus_card;
return true;
}
return false;
},
async updateCusCard(payload) {
let res = await updateCusCard(payload);
if (res.code === 200) {
this.cusCard = payload;
return true;
}
return false;
}
},
persist: true
})

@ -1,4 +1,4 @@
import { getUserInfo, setUserTpl } from "@/api"; import { getUserInfo, setUserTpl, toggleSendWithAD } from "@/api";
export default { export default {
namespaced: true, namespaced: true,
@ -18,6 +18,9 @@ export default {
setTpl(state, payload) { setTpl(state, payload) {
state.userInfo.nc_template = payload; state.userInfo.nc_template = payload;
}, },
setSendWithAd(state, payload) {
state.userInfo.is_send_ad = payload;
}
}, },
actions: { actions: {
async getUserInfo(context) { async getUserInfo(context) {
@ -32,5 +35,15 @@ export default {
context.commit("setTpl", payload); context.commit("setTpl", payload);
} }
}, },
async setSendWithAd(context, payload) {
console.log('payload',payload);
let res = await toggleSendWithAD(payload);
if (res.code === 200) {
context.commit("setSendWithAd", payload);
return true;
}
return false;
}
}, },
}; };

@ -0,0 +1,5 @@
import { createPinia } from 'pinia';
const pinia = createPinia();
export default pinia;

@ -0,0 +1,45 @@
import { defineStore } from 'pinia'
import { getUserData } from "@/api/user";
import { toggleSendWithAD,setUserTpl } from "@/api";
export const useUserStore = defineStore('user', {
state: () => {
return {
userData: {
is_send_ad: 0,
nc_template: 0,
nfc_template: 0,
},
}
},
getters: {
},
actions: {
async getUserData() {
console.log('store get userData');
var res = await getUserData();
if (res.code === 200) {
this.userData = res.data
}
},
async setSendWithAd(payload){
let res = await toggleSendWithAD(payload);
if (res.code === 200) {
this.userData.is_send_ad = payload
return true;
}
return false;
},
async setUserTpl(payload) {
let res = await setUserTpl(payload);
if (res.code === 200) {
this.userData.nc_template = payload
return true;
}
return false;
},
},
persist: true
})

@ -0,0 +1,52 @@
function genAdCard(ctx,option) {
const { json5: vcard } = ctx;
return {
type: "flex",
altText: "廣告卡片",
contents: {
type: "carousel",
contents: [
ctx.contents,
{
"type": "bubble",
"size":"giga",
"hero": {
"type": "image",
"url": option.ad_image,
"size": "full",
"aspectMode": "cover",
"aspectRatio": "5:2",
"action": {
"type": "uri",
"label": option.ad_title,
"uri": option.ad_link
}
},
"body": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": option.ad_title,
"weight": "bold",
"size": "xl",
"color": "#333333"
},
{
"type": "text",
"text": option.ad_desc,
"color": "#666666",
"size": "md",
"wrap": true
}
]
}
}
]
},
};
}
export { genAdCard };

@ -168,13 +168,13 @@ function genCard(vcard) {
{ {
"type": "image", "type": "image",
"url": "${vcard.avatar}", "url": "${vcard.avatar}",
"size": "xs", "size": "full",
"action": { "action": {
"type": "uri", "type": "uri",
"label": "action", "label": "action",
"uri": "${vcard.nfcurl}&cardid=1" "uri": "${vcard.nfcurl}"
}
} }
},
`; `;
} else { } else {
vcardAvatar = ""; vcardAvatar = "";
@ -227,6 +227,8 @@ function genCard(vcard) {
"body": { "body": {
"type": "box", "type": "box",
"layout": "vertical", "layout": "vertical",
"height": "290px",
"backgroundColor": "#333333",
"contents": [ "contents": [
{ {
"type": "image", "type": "image",
@ -238,14 +240,23 @@ function genCard(vcard) {
"action": { "action": {
"type": "uri", "type": "uri",
"label": "action", "label": "action",
"uri": "${vcard.nfcurl}&cardid=1" "uri": "${vcard.nfcurl}"
} }
}, },
{
"type": "box",
"layout": "vertical",
"contents": [
{ {
"type": "box", "type": "box",
"layout": "vertical", "layout": "vertical",
"contents": [ "contents": [
${vcardAvatar} ${vcardAvatar}
],
"width": "80px",
"height": "80px",
"cornerRadius": "50px"
},
{ {
"type": "text", "type": "text",
"text": "${vcard.company}", "text": "${vcard.company}",
@ -254,18 +265,14 @@ function genCard(vcard) {
"weight": "bold", "weight": "bold",
"wrap": true, "wrap": true,
"align": "center", "align": "center",
"margin": "sm", "margin": "sm"
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=1"
}
} }
], ],
"position": "absolute", "position": "absolute",
"offsetTop": "13%", "offsetTop": "8%",
"offsetStart": "3%", "offsetStart": "3%",
"width": "26%" "width": "26%",
"alignItems": "center"
}, },
{ {
"type": "box", "type": "box",
@ -284,7 +291,7 @@ function genCard(vcard) {
"margin": "xs" "margin": "xs"
} }
], ],
"backgroundColor": "#06c755", "backgroundColor": "#222222",
"width": "100%", "width": "100%",
"cornerRadius": "5px", "cornerRadius": "5px",
"action": { "action": {
@ -308,16 +315,41 @@ function genCard(vcard) {
"margin": "xs" "margin": "xs"
} }
], ],
"backgroundColor": "#ffcc5b", "backgroundColor": "#222222",
"width": "100%",
"cornerRadius": "5px",
"margin": "sm",
"paddingTop": "5px",
"paddingBottom": "5px",
"action": {
"type": "uri",
"label": "action",
"uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1&tpl=0"
}
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "收藏名片",
"margin": "xs",
"color": "#ffffff",
"weight": "bold",
"align": "center"
}
],
"margin": "sm",
"width": "100%", "width": "100%",
"backgroundColor": "#222222",
"cornerRadius": "5px", "cornerRadius": "5px",
"margin": "md",
"paddingTop": "5px", "paddingTop": "5px",
"paddingBottom": "5px", "paddingBottom": "5px",
"action": { "action": {
"type": "uri", "type": "uri",
"label": "action", "label": "action",
"uri": "${process.env.VUE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1" "uri": "${import.meta.env.VITE_APP_BASE_URL}/home/address?act=add&cardid=${vcard.user_id}"
} }
} }
], ],
@ -357,7 +389,7 @@ function genCard(vcard) {
"action": { "action": {
"type": "uri", "type": "uri",
"label": "action", "label": "action",
"uri": "${vcard.nfcurl}&cardid=1" "uri": "${vcard.nfcurl}"
} }
} }
] ]
@ -367,7 +399,7 @@ function genCard(vcard) {
"layout": "baseline", "layout": "baseline",
"contents": [], "contents": [],
"backgroundColor": "#d5602d", "backgroundColor": "#d5602d",
"height": "3px", "height": "1px",
"margin": "lg" "margin": "lg"
}, },
${vcardPhone} ${vcardPhone}
@ -385,7 +417,7 @@ function genCard(vcard) {
], ],
"position": "absolute", "position": "absolute",
"offsetTop": "12%", "offsetTop": "12%",
"offsetStart": "35%", "offsetStart": "37%",
"offsetEnd": "5%" "offsetEnd": "5%"
} }
], ],

@ -1,339 +1,473 @@
function genCard(vcard) { function genCard(vcard) {
// 名片預覽
let vcardLink; let vcardLink;
if (vcard.url.trim().length > 0) { if (vcard.url.trim().length > 0) {
if (vcard.nc_func.indexOf("nourl") !== -1) { if (vcard.nc_func.indexOf("nourl") !== -1) {
vcardLink = { vcardLink = `
type: "text", {
text: vcard.url, "type": "box",
color: "#FFFFFF", "layout": "baseline",
align: "end", "margin": "md",
}; "paddingStart": "lg",
"contents": [
{
"type": "icon",
"url": "https://369cycle.zltest.com.tw/tggo/template/icon/link.png",
"size": "sm",
"offsetTop": "xs",
"offsetEnd": "md"
},
{
"type": "text",
"text": "${vcard.url}",
"color": "#6c6664",
"size": "sm"
}
]
},
`;
} else { } else {
vcardLink = { vcardLink = `
type: "text", {
text: vcard.url, "type": "box",
color: "#FFFFFF", "layout": "baseline",
align: "end", "margin": "md",
action: { "paddingStart": "lg",
type: "uri", "contents": [
label: "action", {
uri: vcard.url, "type": "icon",
"url": "https://369cycle.zltest.com.tw/tggo/template/icon/link.png",
"size": "sm",
"offsetTop": "xs",
"offsetEnd": "md"
},
{
"type": "text",
"text": "${vcard.url}",
"color": "#6c6664",
"size": "sm",
"action": {
"type": "uri",
"label": "yahoo",
"uri": "${vcard.url}"
}
}
]
}, },
}; `;
} }
} else { } else {
vcardLink = { vcardLink = "";
type: "text",
text: " ",
color: "#FFFFFF",
align: "end",
};
} }
let vcardAddr; let vcardAddr;
if (vcard.address.trim().length > 0) { if (vcard.address.trim().length > 0) {
vcardAddr = { vcardAddr = `
type: "box",
layout: "vertical",
contents: [
{
type: "text",
text: vcard.address.substr(0, 3),
size: "sm",
},
{ {
type: "text", "type": "box",
text: "layout": "baseline",
vcard.address.substr(3).length > 0 ? vcard.address.substr(3) : " ", "margin": "md",
size: "sm", "paddingStart": "lg",
wrap: true, "contents": [
maxLines: 2, {
"type": "icon",
"url": "https://369cycle.zltest.com.tw/tggo/template/icon/map.png",
"size": "sm",
"offsetTop": "xs",
"offsetEnd": "md"
}, },
], {
position: "absolute", "type": "text",
offsetTop: "30%", "text": "${vcard.address}",
offsetStart: "25%", "color": "#6c6664",
width: "40%", "size": "sm",
height: "60px", "wrap": true,
action: { "action": {
type: "uri", "type": "uri",
label: "action", "label": "action",
uri: `https://www.google.com.tw/maps/place/${encodeURIComponent( "uri": "https://www.google.com.tw/maps/place/${encodeURIComponent(
vcard.address vcard.address
)}`, )}"
}
}
]
}, },
}; `;
} else { } else {
vcardAddr = { vcardAddr = "";
type: "box",
layout: "vertical",
contents: [
{
type: "text",
text: " ",
size: "sm",
},
],
position: "absolute",
offsetTop: "30%",
offsetStart: "25%",
width: "40%",
height: "60px",
};
}
if (vcard.title.trim().length == 0) {
vcard.title = " ";
} }
let vcardTel; let vcardTel;
if (vcard.tel.trim().length == 0) { if (vcard.tel.trim().length > 0) {
vcardTel = { vcardTel = `
type: "text", {
text: " ", "type": "box",
align: "end", "layout": "baseline",
}; "margin": "md",
} else { "paddingStart": "lg",
vcardTel = { "contents": [
type: "text", {
text: vcard.tel, "type": "icon",
align: "end", "url": "https://369cycle.zltest.com.tw/tggo/template/icon/phone.png",
action: { "size": "sm",
type: "uri", "offsetTop": "xs",
label: "action", "offsetEnd": "md"
uri: "tel:" + vcard.tel,
}, },
}; {
"type": "text",
"text": "${vcard.tel}",
"color": "#6c6664",
"size": "sm",
"action": {
"type": "uri",
"label": "action",
"uri": "tel:${vcard.tel}"
}
}
]
},
`;
} else {
vcardTel = "";
} }
let vcardPhone; let vcardPhone;
if (vcard.phone.trim().length == 0) { if (vcard.phone.trim().length > 0) {
vcardPhone = { vcardPhone = `
type: "text", {
text: " ", "type": "box",
align: "end", "layout": "baseline",
}; "margin": "md",
} else { "paddingStart": "lg",
vcardPhone = { "contents": [
type: "text", {
text: vcard.phone, "type": "icon",
align: "end", "url": "https://369cycle.zltest.com.tw/tggo/template/icon/phone.png",
action: { "size": "sm",
type: "uri", "offsetTop": "xs",
label: "action", "offsetEnd": "md"
uri: "tel:" + vcard.phone, },
{
"type": "text",
"text": "${vcard.phone}",
"size": "sm",
"color": "#6c6664",
"action": {
"type": "uri",
"label": "action",
"uri": "tel:${vcard.phone}"
}
}
]
}, },
}; `;
} else {
vcardPhone = "";
} }
let vcardAvatar; let vcardAvatar;
if (vcard.avatar.trim().length > 0) { if (vcard.avatar.trim().length > 0) {
vcardAvatar = { vcardAvatar = `
type: "image", {
url: vcard.avatar, "type": "image",
action: { "url": "${vcard.avatar}",
type: "uri", "size": "full",
label: "action", "aspectRatio": "1:1",
uri: vcard.nfcurl + "&cardid=1", "aspectMode": "cover",
}, "align": "center",
aspectMode: "cover", "gravity": "center",
size: "full", "action": {
}; "type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=1"
}
}
`;
} else { } else {
vcardAvatar = { vcardAvatar = "";
type: "text",
text: " ",
size: "xs",
};
} }
let vcardEmail; let vcardEmail;
if (vcard.email.trim().length > 0) { if (vcard.email.trim().length > 0) {
vcardEmail = { vcardEmail = `
type: "text", {
text: vcard.email, "type": "box",
color: "#333334", "layout": "baseline",
size: "sm", "margin": "md",
weight: "bold", "paddingStart": "lg",
action: { "contents": [
type: "uri", {
label: "action", "type": "icon",
uri: `mailto:${vcard.email}`, "url": "https://369cycle.zltest.com.tw/tggo/template/icon/mail.png",
"size": "sm",
"offsetTop": "xs",
"offsetEnd": "md"
},
{
"type": "text",
"text": "${vcard.email}",
"color": "#6c6664",
"size": "md",
"action": {
"type": "uri",
"label": "action",
"uri": "mailto:${vcard.email}"
}
}
]
}, },
align: "end", `;
};
} else { } else {
vcardEmail = { vcardEmail = "";
type: "text",
text: " ",
color: "#333334",
size: "sm",
weight: "bold",
align: "end",
};
} }
let card = { // 名片發送
altText: "UTel電子名片",
type: "flex", let card = `
contents: { {
type: "bubble", "altText": "UTel電子名片",
size: "giga", "type": "flex",
body: { "contents":
type: "box", {
layout: "vertical", "type": "bubble",
contents: [ "size": "giga",
{ "body": {
type: "image", "type": "box",
url: process.env.VUE_APP_BASE_URL+"/images/tpl02_bg.png", "layout": "vertical",
size: "full", "height": "290px",
aspectMode: "cover", "contents": [
aspectRatio: "4:3", {
gravity: "top", "type": "box",
"layout": "vertical",
"contents": [
{
"type": "image",
"size": "full",
"position": "relative",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-03h.png",
"aspectRatio": "4:1",
"aspectMode": "cover"
}
],
"position": "absolute",
"width": "100%",
"justifyContent": "flex-end",
"height": "100%",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}"
}
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "horizontal",
contents: [vcardAvatar], "contents": [
position: "absolute", {
offsetTop: "13%", "type": "box",
offsetStart: "3%", "layout": "vertical",
width: "75px", "contents": [
height: "75px", {
cornerRadius: "100px", "type": "box",
"layout": "vertical",
"contents": [
${vcardAvatar}
],
"width": "90px",
"cornerRadius": "xl"
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "justifyContent": "space-between",
{ "width": "80%",
type: "box", "contents": [
layout: "vertical", {
contents: [ "type": "button",
{ "action": {
type: "text", "type": "uri",
text: "加入好友", "label": "加入好友",
align: "center", "uri": "https://line.naver.jp/ti/p/~${vcard.line}"
color: "#ffffff",
weight: "bold",
margin: "xs",
size: "xs",
}, },
], "color": "#755483",
backgroundColor: "#ffcc5b", "height": "sm",
width: "100%", "style": "primary",
cornerRadius: "5px", "margin": "xs"
action: {
type: "uri",
label: "action",
uri: "https://line.naver.jp/ti/p/~" + vcard.line,
}, },
paddingTop: "5px", {
paddingBottom: "5px", "type": "button",
"action": {
"type": "uri",
"label": "分享名片",
"uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1&tpl=1"
},
"color": "#93476e",
"height": "sm",
"style": "primary",
"margin": "xs"
}, },
{ {
type: "box", "type": "button",
layout: "vertical", "action": {
contents: [ "type": "uri",
{ "label": "收藏名片",
type: "text", "uri": "${import.meta.env.VITE_APP_BASE_URL}/home/address?act=add&cardid=${vcard.user_id}"
text: "分享名片",
align: "center",
color: "#ffffff",
weight: "bold",
margin: "xs",
size: "xs",
}, },
"color": "#c73f6d",
"height": "sm",
"style": "primary",
"margin": "xs"
}
], ],
backgroundColor: "#ffcc5b", "margin": "xxl"
width: "100%", }
cornerRadius: "5px",
margin: "md",
paddingTop: "5px",
paddingBottom: "5px",
},
], ],
position: "absolute", "paddingTop": "5%",
offsetStart: "10%", "paddingBottom": "5%",
width: "20%", "justifyContent": "space-between",
offsetBottom: "16%", "width": "35%",
action: { "alignItems": "center",
type: "uri", "height": "100%",
label: "action", "position": "relative"
uri: `${process.env.VUE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1`,
},
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
{ {
type: "text", "type": "box",
text: vcard.name, "layout": "vertical",
"contents": [
{
"type": "text",
"text": "Company",
"size": "3xl",
"weight": "bold",
"color": "#c6b0c9",
"offsetBottom": "sm",
"offsetEnd": "md"
}, },
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "${vcard.company}",
"color": "#ffffff",
"size": "md"
}
],
"backgroundColor": "#6c6d8b",
"paddingTop": "sm",
"paddingBottom": "sm",
"paddingStart": "lg",
"cornerRadius": "xxl",
"paddingEnd": "lg",
"position": "absolute",
"offsetTop": "xxl"
}
], ],
position: "absolute", "cornerRadius": "15px",
offsetTop: "13%", "alignItems": "flex-end",
offsetStart: "25%", "position": "relative"
width: "90px",
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
{ {
type: "text", "type": "box",
text: vcard.title, "layout": "vertical",
"contents": [
{
"type": "text",
"text": "${vcard.title}",
"size": "md",
"weight": "bold",
"color": "#888888"
}
]
}, },
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "${vcard.name}",
"size": "xxl",
"weight": "bold"
}
]
}
], ],
position: "absolute", "alignItems": "flex-start",
offsetTop: "13%", "justifyContent": "space-between"
offsetStart: "51%",
width: "50%",
}, },
vcardAddr, {
{ "type": "separator",
type: "box", "color": "#93476e",
layout: "vertical", "margin": "sm"
contents: [vcardPhone, vcardTel],
position: "absolute",
offsetTop: "30%",
offsetEnd: "5%",
width: "30%",
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
${vcardTel}
${vcardPhone}
${vcardLink}
${vcardEmail}
${vcardAddr}
{ {
type: "text", "position": "absolute",
text: vcard.company, "width": "1px",
size: "lg", "height": "1px",
color: "#EFEFEF", "backgroundColor": "#333333",
align: "end", "type": "box",
weight: "bold", "layout": "vertical",
}, "contents": [
vcardLink, {
"type": "separator"
}
]
}
], ],
position: "absolute", "margin": "xs",
offsetTop: "65%", "backgroundColor": "#ffffff95",
offsetEnd: "5%", "paddingTop": "sm",
width: "60%", "paddingBottom": "lg"
}, }
], ],
paddingAll: "0px", "height": "100%",
action: { "position": "relative",
type: "uri", "width": "65%",
label: "action", "paddingStart": "lg",
uri: vcard.nfcurl + "&cardid=1", "paddingEnd": "md",
}, "paddingBottom": "lg"
}, }
}, ],
}; "height": "100%",
return { card: JSON.stringify(card) }; "alignItems": "flex-start"
}
],
"paddingAll": "0px",
"justifyContent": "center",
"alignItems": "center",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=2"
}
}
}
}
`;
return { card };
} }
export { genCard }; export { genCard };

@ -1,368 +1,371 @@
function genCard(vcard) { function genCard(vcard) {
// 名片預覽
let vcardLink; let vcardLink;
if (vcard.url.trim().length > 0) { if (vcard.url.trim().length > 0) {
if (vcard.nc_func.indexOf("nourl") !== -1) { if (vcard.nc_func.indexOf("nourl") !== -1) {
vcardLink = { vcardLink = `{
type: "box", "type": "text",
layout: "baseline", "text": "${vcard.url}",
contents: [ "color": "#6c6664",
{ "size": "md"
type: "text",
text: vcard.url,
color: "#333334",
size: "sm",
weight: "bold",
align: "end",
}, },
], `;
spacing: "lg",
margin: "xs",
};
} else { } else {
vcardLink = { vcardLink = `
type: "box",
layout: "baseline",
contents: [
{ {
type: "text", "type": "text",
text: vcard.url, "text": "${vcard.url}",
color: "#333334", "color": "#6c6664",
size: "sm", "size": "md",
action: { "action": {
type: "uri", "type": "uri",
label: "action", "label": "yahoo",
uri: vcard.url, "uri": "${vcard.url}"
}, }
weight: "bold",
align: "end",
}, },
], `;
spacing: "lg",
margin: "xs",
};
} }
} else { } else {
vcardLink = { vcardLink = "";
type: "box",
layout: "baseline",
contents: [
{
type: "text",
text: " ",
color: "#333334",
size: "sm",
weight: "bold",
align: "end",
},
],
spacing: "lg",
margin: "xs",
};
} }
let vcardAddr; let vcardAddr;
if (vcard.address.trim().length > 0) { if (vcard.address.trim().length > 0) {
vcardAddr = { vcardAddr = `
type: "box",
layout: "vertical",
contents: [
{ {
type: "text", "type": "text",
text: vcard.address, "text": "${vcard.address}",
weight: "bold", "color": "#6c6664",
color: "#333334", "size": "md",
size: "sm", "action": {
align: "end", "type": "uri",
action: { "label": "action",
type: "uri", "uri": "https://www.google.com.tw/maps/place/${encodeURIComponent(
label: "action",
uri: `https://www.google.com.tw/maps/place/${encodeURIComponent(
vcard.address vcard.address
)}`, )}"
}, },
wrap: true, "wrap": true,
"align": "end"
}, },
], `;
spacing: "lg",
margin: "xs",
};
} else { } else {
vcardAddr = { vcardAddr = "";
type: "box",
layout: "vertical",
contents: [
{
type: "text",
text: " ",
weight: "bold",
color: "#333334",
size: "sm",
align: "end",
wrap: true,
},
],
spacing: "lg",
margin: "xs",
};
} }
if (vcard.title.trim().length == 0) { let vcardTel;
vcard.title = " ";
}
if (vcard.tel.trim().length == 0) { if (vcard.tel.trim().length > 0) {
vcard.tel = " "; vcardTel = `
{
"type": "text",
"text": "${vcard.tel}",
"color": "#6c6664",
"size": "md",
"action": {
"type": "uri",
"label": "action",
"uri": "tel:${vcard.tel}"
}
},
`;
} else {
vcardTel = "";
} }
let vcardPhone; let vcardPhone;
if (vcard.phone.trim().length == 0) { if (vcard.phone.trim().length > 0) {
vcard.phone = " "; vcardPhone = `
{
"type": "text",
"text": "${vcard.phone}",
"size": "lg",
"color": "#ffffff",
"action": {
"type": "uri",
"label": "action",
"uri": "tel:${vcard.phone}"
}
}
`;
} else {
vcardPhone = "";
} }
let vcardAvatar; let vcardAvatar;
if (vcard.avatar.trim().length > 0) { if (vcard.avatar.trim().length > 0) {
vcardAvatar = { vcardAvatar = `
type: "image", {
url: vcard.avatar, "type": "image",
action: { "url": "${vcard.avatar}",
type: "uri", "size": "full",
label: "action", "aspectRatio": "1:1",
uri: vcard.nfcurl + "&cardid=1", "aspectMode": "cover",
}, "action": {
}; "type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=1"
}
}
`;
} else { } else {
vcardAvatar = { vcardAvatar = "";
type: "text",
text: " ",
size: "xs",
};
} }
let vcardEmail; let vcardEmail;
if (vcard.email.trim().length > 0) { if (vcard.email.trim().length > 0) {
vcardEmail = { vcardEmail = `
type: "text", {
text: vcard.email, "type": "text",
color: "#333334", "text": "${vcard.email}",
size: "sm", "color": "#6c6664",
weight: "bold", "size": "md",
action: { "action": {
type: "uri", "type": "uri",
label: "action", "label": "action",
uri: `mailto:${vcard.email}`, "uri": "mailto:${vcard.email}"
}
}, },
align: "end", `;
};
} else { } else {
vcardEmail = { vcardEmail = "";
type: "text",
text: " ",
color: "#333334",
size: "sm",
weight: "bold",
align: "end",
};
} }
let card = { // 名片發送
altText: "UTel電子名片",
type: "flex", let card = `
contents: {
type: "bubble",
size: "giga",
body: {
type: "box",
layout: "vertical",
contents: [
{ {
type: "image", "altText": "UTel電子名片",
url: process.env.VUE_APP_BASE_URL+"/images/jcibg.png", "type": "flex",
size: "full", "contents":
aspectMode: "fit",
aspectRatio: "4:3",
gravity: "top",
},
{ {
type: "box", "type": "bubble",
layout: "vertical", "size": "giga",
contents: [ "body": {
vcardAvatar, "type": "box",
"layout": "vertical",
"height": "290px",
"contents": [
{ {
type: "text", "position": "absolute",
text: "大同國際\n青年商會", "type": "image",
wrap: true, "url": "https://369cycle.zltest.com.tw/tggo/template/bg-02h.png",
align: "center", "size": "full",
margin: "md", "aspectRatio": "2:3",
}, "aspectMode": "cover"
],
position: "absolute",
offsetTop: "13%",
offsetStart: "2%",
width: "21%",
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "horizontal",
contents: [ "contents": [
{ {
type: "text", "type": "box",
text: "加入好友", "layout": "vertical",
align: "center", "contents": [
color: "#ffffff",
weight: "bold",
margin: "xs",
},
],
backgroundColor: "#06c755",
width: "100%",
cornerRadius: "5px",
action: {
type: "uri",
label: "action",
uri: "https://line.naver.jp/ti/p/~" + vcard.line,
},
},
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
{ {
type: "text", "type": "text",
text: "分享名片", "text": "${vcard.name}",
align: "center", "size": "xl",
color: "#ffffff", "weight": "bold",
weight: "bold", "color": "#ffffff",
margin: "xs", "margin": "sm"
}, }
],
backgroundColor: "#ffcc5b",
width: "100%",
cornerRadius: "5px",
margin: "md",
},
], ],
position: "absolute", "backgroundColor": "#bf4c32",
offsetStart: "2%", "paddingStart": "10px",
width: "20%", "paddingEnd": "5px"
offsetBottom: "8%",
action: {
type: "uri",
label: "action",
uri: `${process.env.VUE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1`,
},
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
{
type: "box",
layout: "vertical",
contents: [
{ {
type: "text", "type": "text",
text: vcard.name, "text": "${vcard.title}",
size: "lg", "size": "md",
color: "#4EA2D9", "weight": "regular",
weight: "bold", "color": "#ffffff",
align: "end", "action": {
}, "type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=1"
}
}
], ],
"backgroundColor": "#e5b164",
"paddingStart": "xxl",
"paddingEnd": "5px",
"offsetEnd": "5px",
"margin": "sm",
"paddingBottom": "xs",
"paddingTop": "2px"
}, },
{ {
type: "box", "type": "box",
layout: "baseline", "layout": "vertical",
contents: [ "contents": [${vcardPhone}],
{ "backgroundColor": "#7aa567",
type: "text", "margin": "xs",
text: vcard.title, "paddingStart": "5px",
color: "#333334", "paddingEnd": "5px"
size: "md", }
weight: "bold",
align: "end",
},
], ],
spacing: "lg", "alignItems": "flex-end",
"width": "50%",
"paddingEnd": "xl"
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [${vcardAvatar}],
{ "cornerRadius": "20px",
type: "separator", "borderWidth": "bold",
}, "borderColor": "#ffffff",
"margin": "none",
"width": "100px"
}
], ],
height: "20px", "alignItems": "center",
"paddingTop": "3%",
"justifyContent": "center"
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
{ {
type: "text", "type": "box",
text: vcard.company, "layout": "horizontal",
color: "#4EA2D9", "contents": [
size: "md", {
weight: "bold", "type": "box",
align: "end", "layout": "vertical",
}, "contents": [
${vcardTel}
${vcardLink}
${vcardEmail}
${vcardAddr}
{
"position": "absolute",
"width": "1px",
"height": "1px",
"backgroundColor": "#333333",
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "separator"
}
]
}
], ],
spacing: "lg", "alignItems": "flex-end",
margin: "xs", "paddingEnd": "xl"
}, },
vcardAddr,
{ {
type: "box", "type": "box",
layout: "horizontal", "layout": "vertical",
contents: [ "justifyContent": "space-between",
"contents": [
{ {
type: "text", "type": "button",
text: vcard.tel, "action": {
align: "end", "type": "uri",
size: "sm", "label": "加入好友",
color: "#333334", "uri": "https://line.naver.jp/ti/p/~${vcard.line}"
weight: "bold", },
"color": "#464757",
"height": "sm",
"style": "primary"
}, },
{ {
type: "text", "type": "button",
text: vcard.phone, "action": {
size: "sm", "type": "uri",
align: "end", "label": "分享名片",
weight: "bold", "uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1&tpl=2"
}, },
], "color": "#464757",
"height": "sm",
"margin": "sm",
"style": "primary"
}, },
vcardLink,
{ {
type: "box", "type": "button",
layout: "baseline", "action": {
contents: [vcardEmail], "type": "uri",
spacing: "lg", "label": "收藏名片",
margin: "xs", "uri": "${import.meta.env.VITE_APP_BASE_URL}/home/address?act=add&cardid=${vcard.user_id}"
}, },
"color": "#464757",
"height": "sm",
"margin": "sm",
"style": "primary"
}
], ],
position: "absolute", "width": "100px"
offsetTop: "30%", }
offsetStart: "35%",
offsetEnd: "5%",
},
], ],
paddingAll: "0px", "alignItems": "flex-end"
action: { }
type: "uri", ],
label: "action", "justifyContent": "space-between"
uri: vcard.nfcurl + "&cardid=1", }
}, ],
}, "width": "95%",
"height": "92%",
"borderWidth": "light",
"borderColor": "#bbbbbb",
"paddingAll": "5px",
"justifyContent": "space-between",
"cornerRadius": "lg"
}, },
}; {
return { card: JSON.stringify(card) }; "position": "absolute",
"type": "box",
"layout": "vertical",
"height": "25px",
"justifyContent": "center",
"alignItems": "center",
"paddingStart": "lg",
"paddingEnd": "lg",
"offsetTop": "sm",
"offsetStart": "sm",
"cornerRadius": "15px",
"backgroundColor": "#ffffff",
"contents": [
{
"type": "text",
"text": "${vcard.company}",
"color": "#e5b164",
"size": "md"
}
]
}
],
"paddingAll": "0px",
"justifyContent": "center",
"alignItems": "center",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=3"
}
}
}
}
`;
return { card };
} }
export { genCard }; export { genCard };

@ -1,348 +1,338 @@
function genCard(vcard) { function genCard(vcard) {
// 名片預覽
let vcardLink; let vcardLink;
if (vcard.url.trim().length > 0) { if (vcard.url.trim().length > 0) {
if (vcard.nc_func.indexOf("nourl") !== -1) { if (vcard.nc_func.indexOf("nourl") !== -1) {
vcardLink = { vcardLink = `{
type: "box", "type": "text",
layout: "baseline", "text": "${vcard.url}",
contents: [ "color": "#ffffff",
{ "size": "sm"
type: "text",
text: vcard.url,
color: "#333334",
size: "sm",
weight: "bold",
align: "end",
}, },
], `;
spacing: "lg",
margin: "xs",
};
} else { } else {
vcardLink = { vcardLink = `
type: "box",
layout: "baseline",
contents: [
{ {
type: "text", "type": "text",
text: vcard.url, "text": "${vcard.url}",
color: "#333334", "color": "#ffffff",
size: "sm", "size": "sm",
action: { "action": {
type: "uri", "type": "uri",
label: "action", "label": "action",
uri: vcard.url, "uri": "${vcard.url}"
}, }
weight: "bold",
align: "end",
}, },
], `;
spacing: "lg",
margin: "xs",
};
} }
} else { } else {
vcardLink = { vcardLink = "";
type: "box", }
layout: "baseline",
contents: [ let vcardAvatar;
if (vcard.avatar.trim().length > 0) {
vcardAvatar = `
{ {
type: "text", "type": "image",
text: " ", "url": "${vcard.avatar}",
color: "#333334", "size": "full",
size: "sm", "aspectRatio": "1:1",
weight: "bold", "aspectMode": "cover",
align: "end", "action": {
}, "type": "uri",
], "label": "action",
spacing: "lg", "uri": "${vcard.nfcurl}&cardid=1"
margin: "xs", }
}; }
`;
} else {
vcardAvatar = "";
} }
let vcardAddr; let vcardAddr;
if (vcard.address.trim().length > 0) { if (vcard.address.trim().length > 0) {
vcardAddr = { vcardAddr = `
type: "box",
layout: "vertical",
contents: [
{ {
type: "text", "type": "text",
text: vcard.address, "text": "${vcard.address}",
weight: "bold", "color": "#ffffff",
color: "#333334", "size": "sm",
size: "sm", "margin": "sm",
align: "end", "wrap": true,
action: { "action": {
type: "uri", "type": "uri",
label: "action", "label": "action",
uri: `https://www.google.com.tw/maps/place/${encodeURIComponent( "uri": "https://www.google.com.tw/maps/place/${encodeURIComponent(
vcard.address vcard.address
)}`, )}"
}, }
wrap: true,
}, },
], `;
spacing: "lg",
margin: "xs",
};
} else { } else {
vcardAddr = { vcardAddr = "";
type: "box",
layout: "vertical",
contents: [
{
type: "text",
text: " ",
weight: "bold",
color: "#333334",
size: "sm",
align: "end",
wrap: true,
},
],
spacing: "lg",
margin: "xs",
};
} }
if (vcard.title.trim().length == 0) { let vcardTel;
vcard.title = " "; if (vcard.tel.trim().length > 0) {
vcardTel = `
{
"type": "text",
"text": "${vcard.tel}",
"color": "#ffffff",
"size": "lg",
"wrap": true,
"action": {
"type": "uri",
"label": "action",
"uri": "tel:${vcard.tel}"
} }
},
if (vcard.tel.trim().length == 0) { `;
vcard.tel = " "; } else {
vcardTel = "";
} }
let vcardPhone; let vcardPhone;
if (vcard.phone.trim().length > 0) {
if (vcard.phone.trim().length == 0) { vcardPhone = `
vcard.phone = " "; {
"type": "text",
"text": "${vcard.phone}",
"size": "lg",
"margin": "sm",
"action": {
"type": "uri",
"label": "action",
"uri": "tel:${vcard.phone}"
} }
}
let vcardAvatar; `;
if (vcard.avatar.trim().length > 0) {
vcardAvatar = {
type: "image",
url: vcard.avatar,
action: {
type: "uri",
label: "action",
uri: vcard.nfcurl + "&cardid=1",
},
};
} else { } else {
vcardAvatar = { vcardPhone = "";
type: "text",
text: " ",
size: "xs",
};
} }
let vcardEmail; let vcardEmail;
if (vcard.email.trim().length > 0) { if (vcard.email.trim().length > 0) {
vcardEmail = { vcardEmail = `
type: "text", {
text: vcard.email, "type": "text",
color: "#333334", "text": "${vcard.email}",
size: "sm", "color": "#ffffff",
weight: "bold", "size": "sm",
action: { "margin": "sm",
type: "uri", "action": {
label: "action", "type": "uri",
uri: `mailto:${vcard.email}`, "label": "action",
"uri": "mailto:${vcard.email}"
}
}, },
align: "end", `;
};
} else { } else {
vcardEmail = { vcardEmail = "";
type: "text",
text: " ",
color: "#333334",
size: "sm",
weight: "bold",
align: "end",
};
} }
let card = { // 名片發送
altText: "UTel電子名片",
type: "flex", let card = `
contents: {
type: "bubble",
size: "giga",
body: {
type: "box",
layout: "vertical",
contents: [
{ {
type: "image", "altText": "UTel電子名片",
size: "full", "type": "flex",
aspectMode: "cover", "contents":
aspectRatio: "4:3",
gravity: "top",
url: process.env.VUE_APP_BASE_URL+"/images/tpl03_bg.png?v=1",
},
{ {
type: "box", "type": "bubble",
layout: "vertical", "size": "giga",
contents: [ "body": {
"type": "box",
"layout": "horizontal",
"height": "290px",
"paddingAll": "0px",
"backgroundColor": "#353e45",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}"
},
"contents": [
{ {
type: "text", "position": "absolute",
text: vcard.company || " ", "type": "box",
size: "xl", "layout": "vertical",
wrap: true, "width": "67%",
}, "height": "100%",
], "justifyContent": "flex-start",
position: "absolute", "offsetEnd": "none",
offsetTop: "5%", "contents": [
offsetStart: "5%", {
width: "60%", "position": "relative",
"type": "image",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-01s.png",
"size": "full",
"aspectRatio": "3:1",
"offsetTop": "15%"
}
]
}, },
{ {
type: "box", "position": "relative",
layout: "vertical", "type": "box",
contents: [vcardAvatar], "layout": "vertical",
position: "absolute", "width": "35%",
offsetTop: "5%", "height": "100%",
offsetEnd: "5%", "paddingAll": "14px",
"justifyContent": "space-between",
"alignItems": "center",
"backgroundColor": "#ffffff",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "box",
"layout": "vertical",
"width": "80%",
"margin": "none",
"borderWidth": "bold",
"borderColor": "#f5c520",
"cornerRadius": "150px",
"contents": [${vcardAvatar}]
}, },
{ {
type: "box", "type": "text",
layout: "horizontal", "text": "${vcard.name}",
contents: [ "size": "xl",
"weight": "bold",
"margin": "md"
},
{ {
type: "text", "type": "text",
text: vcard.name, "text": "${vcard.title}",
size: "lg", "size": "md",
weight: "bold", "weight": "regular",
align: "center", "color": "#666666"
}, },
// { ${vcardPhone}
// type: "text", ]
// text: " ",
// size: "lg",
// weight: "bold",
// color: "#F71646",
// },
],
position: "absolute",
offsetStart: "40%",
offsetTop: "45%",
width: "20%",
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
{ {
type: "text", "type": "text",
text: vcard.title || " ", "text": "收藏名片"
align: "center", }
},
], ],
position: "absolute", "position": "relative",
offsetTop: "55%", "height": "40px",
offsetStart: "40%", "borderWidth": "light",
width: "20%", "borderColor": "#333333",
"cornerRadius": "lg",
"justifyContent": "center",
"alignItems": "center",
"width": "100%",
"action": {
"type": "uri",
"label": "action",
"uri": "${import.meta.env.VITE_APP_BASE_URL}/home/address?act=add&cardid=${vcard.user_id}"
}
}
]
}, },
{ {
type: "box", "position": "relative",
layout: "horizontal", "type": "box",
contents: [ "layout": "vertical",
"width": "66%",
"height": "100%",
"justifyContent": "space-between",
"paddingAll": "14px",
"contents": [
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "contents": [
${vcardTel}
{ {
type: "image", "type": "text",
url: "https://utel.u168.vip/images/icons/web.png", "text": "${vcard.company}",
align: "center", "color": "#ffffff",
size: "xxs", "size": "xl",
"weight": "bold"
}
]
}, },
{ {
type: "text", "type": "box",
text: "我的網站", "layout": "vertical",
align: "center", "contents": [
color: "#FFFFFF", ${vcardLink}
}, ${vcardEmail}
], ${vcardAddr}
flex: 1,
action: {
type: "uri",
label: "action",
uri:
vcard.url.trim().length > 0
? vcard.url
: vcard.nfcurl + "&cardid=1",
},
},
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "horizontal",
contents: [ "justifyContent": "space-between",
"margin": "md",
"contents": [
{ {
type: "image", "type": "box",
url: "https://utel.u168.vip/images/icons/phone.png", "layout": "vertical",
align: "center", "width": "48%",
size: "xxs", "height": "40px",
}, "justifyContent": "center",
"alignItems": "center",
"borderWidth": "light",
"borderColor": "#dddddd",
"cornerRadius": "lg",
"contents": [
{ {
type: "text", "type": "text",
text: vcard.phone, "text": "加入好友",
align: "center", "color": "#dddddd"
color: "#FFFFFF", }
},
], ],
flex: 1, "action": {
action: { "type": "uri",
type: "uri", "label": "action",
label: "action", "uri": "https://line.naver.jp/ti/p/~${vcard.line}"
uri: "tel:" + vcard.phone, }
},
}, },
{ {
type: "box", "type": "box",
layout: "vertical", "layout": "vertical",
contents: [ "width": "48%",
"height": "40px",
"justifyContent": "center",
"alignItems": "center",
"borderWidth": "light",
"borderColor": "#dddddd",
"cornerRadius": "lg",
"contents": [
{ {
type: "image", "type": "text",
url: "https://utel.u168.vip/images/icons/email.png", "text": "分享名片",
align: "center", "color": "#dddddd"
size: "xxs", }
},
{
type: "text",
text: vcard.email,
align: "center",
color: "#FFFFFF",
},
],
flex: 1,
action: {
type: "uri",
label: "action",
uri: "mailto:" + vcard.email,
},
},
],
position: "absolute",
width: "100%",
offsetBottom: "5%",
},
], ],
paddingAll: "0px", "action": {
action: { "type": "uri",
type: "uri", "label": "action",
label: "action", "uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1&tpl=3"
uri: vcard.nfcurl + "&cardid=1", }
}, }
}, ]
}, }
}; ]
console.log(JSON.stringify(card)); }
return { card: JSON.stringify(card) }; ]
}
]
}
}
}
`;
return { card };
} }
export { genCard }; export { genCard };

@ -2,9 +2,9 @@ import { genCard as Card0 } from "./card0.js";
import { genCard as Card1 } from "./card1.js"; import { genCard as Card1 } from "./card1.js";
import { genCard as Card2 } from "./card2.js"; import { genCard as Card2 } from "./card2.js";
import { genCard as Card3 } from "./card3.js"; import { genCard as Card3 } from "./card3.js";
import { genCard as Card4 } from "./card4.js";
export function genCard(opt) { export function genCard(opt) {
console.log(opt.tid)
switch (opt.tid) { switch (opt.tid) {
case 0: case 0:
return Card0(opt.vcard); return Card0(opt.vcard);
@ -18,9 +18,6 @@ export function genCard(opt) {
case 3: case 3:
return Card3(opt.vcard); return Card3(opt.vcard);
break; break;
case 4:
return Card4(opt.vcard);
break;
default: default:
throw new Error("params error"); throw new Error("params error");
break; break;

@ -1,5 +1,6 @@
function genCard(vcard) { function genCard(vcard) {
// 名片預覽 // 名片預覽
console.log('test')
let vcardLink; let vcardLink;
if (vcard.url.trim().length > 0) { if (vcard.url.trim().length > 0) {
if (vcard.nc_func.indexOf("nourl") !== -1) { if (vcard.nc_func.indexOf("nourl") !== -1) {
@ -246,7 +247,7 @@ function genCard(vcard) {
let card = ` let card = `
{ {
"altText": "UTel電子名片", "altText": "UTel電子名片test",
"type": "flex", "type": "flex",
"contents": "contents":
{ {
@ -345,7 +346,7 @@ function genCard(vcard) {
"action": { "action": {
"type": "uri", "type": "uri",
"label": "action", "label": "action",
"uri": "${process.env.VUE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1" "uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1"
} }
} }
], ],

@ -1,5 +1,7 @@
import _ from "lodash"; import _ from "lodash";
const DEFAULT_LINK = 'https://utel.vip';
function vcardUuid(vcard, secret) { function vcardUuid(vcard, secret) {
const hash = CryptoJS.HmacMD5(JSON.stringify(vcard), secret); const hash = CryptoJS.HmacMD5(JSON.stringify(vcard), secret);
const hex = CryptoJS.enc.Hex.stringify(hash); const hex = CryptoJS.enc.Hex.stringify(hash);

@ -0,0 +1,5 @@
// import { useCardStore } from '@/store/card.js';
// import { getCardData } from '@/api/card.js';
// export const initStore = async (pinia) => {
// };

@ -0,0 +1,11 @@
import liff from "@line/liff";
async function initLiff(app) {
await liff.init({ liffId: import.meta.env.VITE_APP_LINE_LIFF_ID });
if (!liff.isLoggedIn()){
liff.login({ redirectUri: window.location.href });
}
app.provide('liff', liff);
}
export default initLiff;

@ -0,0 +1,496 @@
<script setup>
import _ from 'lodash';
import { showToast, showSuccessToast, showConfirmDialog } from 'vant';
import {
getUserFaviList
, getUserCateList
, updateUserCate
, setUserFaviCate
, addUserFavi
, deleteUserFavi
} from '@/api'
import { onMounted, onBeforeMount, ref } from 'vue'
import { useRoute } from 'vue-router';
const route = useRoute();
const setShowPicker = ref(false);
const selectVal1 = ref('all');
const selectVal2 = ref('普通');
const selectOpt1 = ref([{ text: '全部', value: 'all' }]);
const selectOpt2 = ref([{ text: '重要', value: '重要' }, { text: '普通', value: '普通' }]);
const addressList = ref([]);
onBeforeMount(async () => {
if (route.query.act === 'add') {
let res = await addUserFavi({ uf_user_id: route.query.cardid });
}
});
onMounted(async () => {
initData();
getCateList();
});
const initData = async () => {
let res = await getUserFaviList(0);
if (res.code === 200) {
addressList.value = res.data;
}
};
const getCateList = async () => {
let res = await getUserCateList();
if (res.code === 200) {
columns.value = [columns.value[0], ...res.data];
columns2.value = [columns2.value[0], ...res.data];
if (res.data.length > 0) {
modalForm.value.sort = res.data;
} else {
modalForm.value.sort = [_.cloneDeep(defaultCate)];
}
}
}
const handleDeleteFavi = async (id) => {
// vant
showConfirmDialog({
title: '確認刪除',
message:
'是否確認刪除好友?',
cancelButtonText: '取消',
confirmButtonText: '確認',
})
.then(async () => {
let res = await deleteUserFavi(id);
if (res.code === 200) {
initData();
showSuccessToast('刪除成功')
} else {
showToast('刪除失敗')
}
})
.catch(() => {
});
};
const handleGoNfc = (item) => {
window.open(item.nfcurl, '_blank');
};
// START:
const fieldValue = ref('全部-全部');
const showCatePicker = ref(false);
const customFieldName = {
text: 'name',
value: 'id',
children: 'children',
};
const columns = ref([
{
id: 0,
name: '全部',
children: [
{
id: 0,
name: '全部'
}
]
},
]);
const onCateConfirm = async (value) => {
let res = await getUserFaviList(value.selectedValues[1]);
if (res.code === 200) {
addressList.value = res.data;
}
showCatePicker.value = false;
};
const onCateChange = (value) => {
fieldValue.value = value.selectedOptions.map((item) => item.name).join('-');
};
// END:
// START:
const columns2 = ref([
{
id: 0,
name: '未分類',
children: [
{
id: 0,
name: '未分類'
}
]
},
]);
const showChangeCatePicker = ref(false);
const changeUserId = ref('');
const handleChangeCate = (userId) => {
changeUserId.value = userId;
showChangeCatePicker.value = true;
};
const onChangeCateConfirm = async (value) => {
let res = await setUserFaviCate({ uf_user_id: changeUserId.value, cate_id: value.selectedValues[1] });
if (res.code === 200) {
getCateList();
showSuccessToast('更新成功')
} else {
showToast('更新失敗')
}
showChangeCatePicker.value = false;
};
const onChangeCateChange = (value) => {
console.log('Change Category');
};
// END:
// START:
const defaultCate = {
"id": 0,
"name": ""
};
const modalForm = ref({
page: 1,
sort: [_.cloneDeep(defaultCate)]
});
const sel1Change = (value) => {
if (value != 'all') {
let child = modalForm.value.sort[value].children;
let ary = [];
child.forEach((item, i) => {
ary.push({
text: item.name,
value: item.name
})
});
selectOpt2.value = ary;
selectVal2.value = child[0].name;
} else {
selectOpt2.value = [];
selectVal2.value = '';
}
};
const addCard = () => {
modalForm.value.sort.push(_.cloneDeep(defaultCate));
modalForm.value.page = modalForm.value.sort.length;
};
const delCard = (page) => {
if (page > 1) {
modalForm.value.page = page - 1;
}
modalForm.value.sort.splice(page - 1, 1);
};
const addBtn = (page) => {
if (!modalForm.value.sort[page - 1].children) {
modalForm.value.sort[page - 1].children = [];
}
modalForm.value.sort[page - 1].children.push(_.cloneDeep(defaultCate));
};
const moveCard = (type, page) => {
if (type === 0) {
if (page !== 1) {
[modalForm.value.sort[page - 1], modalForm.value.sort[page - 2]] = [
modalForm.value.sort[page - 2],
modalForm.value.sort[page - 1],
];
modalForm.value.page = page - 1;
}
} else {
if (page !== modalForm.value.sort.length) {
[modalForm.value.sort[page], modalForm.value.sort[page - 1]] = [
modalForm.value.sort[page - 1],
modalForm.value.sort[page],
];
modalForm.value.page = page + 1;
}
}
};
const delBtn = (index) => {
modalForm.value.sort[modalForm.value.page - 1].children.splice(index, 1);
if (modalForm.value.sort[modalForm.value.page - 1].children.length === 0) {
delete modalForm.value.sort[modalForm.value.page - 1].children;
}
};
const moveBtn = (type, index) => {
if (type === 0) {
if (index !== 0) {
[
modalForm.value.sort[modalForm.value.page - 1].children[index],
modalForm.value.sort[modalForm.value.page - 1].children[index - 1],
] = [
modalForm.value.sort[modalForm.value.page - 1].children[index - 1],
modalForm.value.sort[modalForm.value.page - 1].children[index],
];
}
} else {
if (index + 1 !== modalForm.value.sort[modalForm.value.page - 1].children.length) {
[
modalForm.value.sort[modalForm.value.page - 1].children[index + 1],
modalForm.value.sort[modalForm.value.page - 1].children[index],
] = [
modalForm.value.sort[modalForm.value.page - 1].children[index],
modalForm.value.sort[modalForm.value.page - 1].children[index + 1],
];
}
}
};
const onSubmit = async () => {
let res = await updateUserCate({ category: modalForm.value.sort })
if (res.code === 200) {
getCateList();
showSuccessToast('更新成功')
// router.push('/member')
} else {
console.log(res.code);
showToast('更新失敗')
}
};
</script>
<template>
<div class="address page">
<van-nav-bar class="bg-skyBlue py-1" left-arrow right-arrow @click-left="$router.push('/')"
@click-right="setShowPicker = true">
<template #title>
<h5 class="text-white mb-1"><strong>通訊錄</strong></h5>
</template>
<template #left>
<h4><i class="fa-solid fa-angle-left text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
<template #right>
<h4><i class="fa-solid fa-gear text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
</van-nav-bar>
<div class="content">
<!-- START: 通訊錄類別 -->
<van-cell-group inset>
<van-field v-model="fieldValue" is-link readonly label="類別" placeholder="通訊錄類別" @click="showCatePicker = true" />
<van-popup v-model:show="showCatePicker" round position="bottom">
<van-picker :columns="columns" :columns-field-names="customFieldName" confirm-button-text=""
cancel-button-text="取消" @cancel="showCatePicker = false" @confirm="onCateConfirm" @change="onCateChange" />
</van-popup>
</van-cell-group>
<!-- END: 通訊錄類別 -->
<van-cell-group inset>
<van-list>
<div class="list-item" v-for="(item, index) in addressList" :data-cateid="item.user_cate_id" :key="index">
<div class="left" @click="handleGoNfc(item)">
<div class="avatar"><img :src="item.avatar"></div>
<div class="text">
<h5 class="name ellipsis">{{ item.real_name }}</h5>
<div class="desc ellipsis">@{{ item.line }}</div>
</div>
</div>
<div class="right">
<van-button size="small" class="border-0" @click="handleChangeCate(item.user_id)">
<h5><i class="fa-solid fa-heart text-darkBlue"></i></h5>
</van-button>
<van-button size="small" class="border-0" :url="`line://ti/p/@${item.line}`">
<h5><i class="fa-solid fa-share-nodes text-darkBlue"></i></h5>
</van-button>
<van-button size="small" class="border-0" @click="handleDeleteFavi(item.id)">
<h5><i class="fa-solid fa-trash text-darkBlue"></i></h5>
</van-button>
</div>
</div>
</van-list>
</van-cell-group>
</div>
<!-- START: 編輯通訊錄 -->
<van-dialog v-model:show="setShowPicker" width="400" showCancelButton confirm-button-text="" @confirm="onSubmit">
<van-form @submit="onSubmit">
<div id="app" class="address-block">
<div class="bg-lightPink px-2 pt-3">
<ul class="nav nav-tabs">
<li class="nav-item" v-for="(card, index) in modalForm.sort" :key="index"
@click="modalForm.page = index + 1">
<button type="button" class="nav-link" :class="{ active: modalForm.page === index + 1 }">
{{ index + 1 }}
</button>
</li>
<li class="nav-item" @click="addCard" v-if="modalForm.sort.length < 10">
<button type="button" class="nav-link">
<i class="fa fa-plus-circle"></i>
</button>
</li>
</ul>
</div>
<van-cell-group class="m-0 pt-2">
<van-field label="調整卡片順序" :border="false" v-if="modalForm.sort.length > 1">
<template #button>
<van-button size="small" class="ml-1 btn-skyBlue" icon="arrow-left"
@click="moveCard(0, modalForm.page)">前移</van-button>
<van-button size="small" class="ml-1 btn-skyBlue" icon="arrow"
@click="moveCard(1, modalForm.page)">後移</van-button>
<van-button size="small" class="ml-1 btn-tomatoRed" icon="delete-o"
@click="delCard(modalForm.page)"></van-button>
</template>
</van-field>
<van-field v-model="modalForm.sort[modalForm.page - 1].name" label="分類名稱" id="vcard-title" input-align="right"
placeholder="請輸入分類名稱" />
<div class="listCnt">
<div class="item" v-for="(btn, index) in modalForm.sort[modalForm.page - 1].children" :key="index">
<van-field v-model="btn.name" id="cardbtn-text-0" placeholder="請輸入子項目名稱" class="bg-transparent">
<template #button>
<van-button size="small" class="bg-transparent border-0" icon="arrow-up" @click="moveBtn(0, index)"
v-if="modalForm.sort[modalForm.page - 1].children.length > 1"></van-button>
<van-button size="small" class="bg-transparent border-0" icon="arrow-down" @click="moveBtn(1, index)"
v-if="modalForm.sort[modalForm.page - 1].children.length > 1"></van-button>
<van-button size="small" class="bg-transparent border-0" icon="delete-o"
@click="delBtn(index)"></van-button>
</template>
</van-field>
</div>
<van-button block class="btn-tomatoRed" icon="add-o" @click="addBtn(modalForm.page)">
<h6>新增按鈕</h6>
</van-button>
</div>
</van-cell-group>
</div>
</van-form>
</van-dialog>
<!-- END: 編輯通訊錄 -->
<van-popup v-model:show="showChangeCatePicker" round position="bottom">
<van-picker :columns="columns2" :columns-field-names="customFieldName" confirm-button-text=""
cancel-button-text="取消" @cancel="showChangeCatePicker = false" @confirm="onChangeCateConfirm"
@change="onChangeCateChange" />
</van-popup>
</div>
</template>
<style lang="less" scoped>
.address {
.content {
min-height: calc(100vh - 54px);
}
.van-list {
.list-item {
display: flex;
align-items: center;
flex-wrap: wrap;
padding: 15px 0;
margin: 0 15px;
border-bottom: 1px #e3e3e3 solid;
.left {
flex: 1 0 0%;
display: flex;
align-items: center;
.avatar {
width: 55px;
min-width: 55px;
aspect-ratio: 1/1;
border-radius: 50%;
margin-right: 10px;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.name {
font-weight: bold;
}
}
.right {
flex: 0 0 auto;
}
.bottom {
flex: 1 0 100%;
border: 1px #e3e3e3 solid;
border-radius: 10px;
padding: 0 10px;
margin: 0;
transition: all .2s;
&.show {
padding: 10px;
margin: 5px 0;
}
}
}
}
.nav-tabs {
.nav-link {
color: #4a677d;
background-color: #fff;
border-color: transparent;
margin-right: 4px;
}
.nav-item.show .nav-link,
.nav-link.active {
color: #fff;
background-color: #4a677d;
border-color: #4a677d #4a677d #4a677d;
}
}
.listCnt {
padding: 15px;
.item {
margin-bottom: 15px;
border: 1px #ddd solid;
border-radius: 5px;
}
}
}
.address-block {
max-height: 80vh;
overflow-y: auto;
}
</style>

@ -1,50 +1,7 @@
<template>
<div>
<van-nav-bar title="授權商務卡片編輯" right-text="" @click-right="$router.push('/')" />
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field
v-model="form.user_id"
label="會員編號"
name="pattern"
placeholder="請輸入想授權的會員編號"
label-width="100"
:rules="[{ required: true, message: '會員編號為必填' }]"
/>
<van-field
v-model="form.a_hour"
label="授權時間(小時)"
name="pattern"
placeholder="請輸入想授權的時間"
label-width="100"
:rules="[{ required: true, message: '授權時間為必填' }]"
/>
</van-cell-group>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
送出
</van-button>
</div>
</van-form>
<table id="auth-list">
<tr>
<th>授權會員</th>
<th>授權時間</th>
<th>操作</th>
</tr>
<tr v-for="v of authList" :key="v.id">
<td>{{v.user_id}}</td>
<td>{{v.auth_time}}</td>
<td @click="handleDelete(v.id)"></td>
</tr>
</table>
</div>
</template>
<script setup> <script setup>
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { Toast } from 'vant'; import { showToast,showSuccessToast } from 'vant';
import { setAuthUser , delAuthUser , getAuthUsers } from '@/api' import { setAuthUser , delAuthUser , getAuthUsers } from '@/api'
@ -57,12 +14,12 @@ const onSubmit = async () =>{
let res = await setAuthUser(form.value); let res = await setAuthUser(form.value);
if(res.code!==200){ if(res.code!==200){
return Toast.fail('授權失敗,'+res.data); return showToast.fail('授權失敗,'+res.data);
} }
genAuthList(); genAuthList();
return Toast.success('授權成功'); return showSuccessToast('授權成功');
} }
// //
@ -84,12 +41,12 @@ const handleDelete = async (id)=>{
console.log(res) console.log(res)
if(res.code!==200){ if(res.code!==200){
return Toast.fail('刪除失敗'); return showToast.fail('刪除失敗');
} }
genAuthList(); genAuthList();
return Toast.success('刪除成功'); return showSuccessToast('刪除成功');
} }
@ -99,15 +56,79 @@ onMounted(()=>{
</script> </script>
<template>
<div class="auth page">
<van-nav-bar class="bg-skyBlue py-1" left-arrow @click-left="$router.push('/')">
<template #title>
<h5 class="text-white mb-1"><strong>授權商務卡片編輯</strong></h5>
</template>
<template #left>
<h4><i class="fa-solid fa-angle-left text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
</van-nav-bar>
<div class="content">
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field
v-model="form.user_id"
label="會員編號"
name="pattern"
placeholder="請輸入想授權的會員編號"
label-width="100"
:rules="[{ required: true, message: '會員編號為必填' }]"
/>
<van-field
v-model="form.a_hour"
label="授權時間(小時)"
name="pattern"
placeholder="請輸入想授權的時間"
label-width="100"
:rules="[{ required: true, message: '授權時間為必填' }]"
/>
<div class="p-3">
<van-button block class="btn-darkBlue" native-type="submit"><i class="fa-solid fa-hand"></i> 確認送出授權</van-button>
</div>
</van-cell-group>
<van-cell-group inset>
<table id="auth-list">
<thead>
<tr>
<th>授權會員</th>
<th>授權時間</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="v of authList" :key="v.id">
<td>{{v.user_id}}</td>
<td>{{v.auth_time}}</td>
<td @click="handleDelete(v.id)"></td>
</tr>
</tbody>
</table>
</van-cell-group>
</van-form>
</div>
</div>
</template>
<style src="@/assets/css/main.css"></style>
<style lang="less" scoped> <style lang="less" scoped>
#auth-list{ table#auth-list{
width: 100%; width: 100%;
td,th{ thead th{
border: 1px solid #ddd; color: #fff;
padding: 3px; background-color: #4a677d;
} }
tr:nth-child(even){ tr:nth-child(even){
background-color: #f2f2f2; background-color: #f2f2f2;
} }
th,td{
padding: 5px 10px;
}
} }
</style> </style>

@ -545,8 +545,8 @@
</template> </template>
<script> <script>
import Footer from "@/components/Footer"; import Footer from "@/components/Footer.vue";
import FlexView from "@/components/FlexView"; import FlexView from "@/components/FlexView.vue";
import { import {
ref, ref,
@ -565,7 +565,7 @@ import { useRouter ,useRoute} from "vue-router";
import axios from "axios"; import axios from "axios";
import _ from "lodash"; import _ from "lodash";
import { Toast } from "vant"; import { showToast,showLoadingToast,showSuccessToast } from "vant";
import { Cropper } from "vue-advanced-cropper"; import { Cropper } from "vue-advanced-cropper";
import "vue-advanced-cropper/dist/style.css"; import "vue-advanced-cropper/dist/style.css";
@ -664,14 +664,14 @@ export default defineComponent({
crop.value.show = false; crop.value.show = false;
Toast.loading({ showLoadingToast({
duration: 0, duration: 0,
message: "圖片上傳中...", message: "圖片上傳中...",
forbidClick: true, forbidClick: true,
}); });
let res = await axios.post( let res = await axios.post(
`${process.env.VUE_APP_API_URL}/card/uploadfile`, `${import.meta.env.VITE_APP_API_URL}/card/uploadfile`,
imgFile, imgFile,
{} {}
); );
@ -679,9 +679,9 @@ export default defineComponent({
if (res.data.code == 200) { if (res.data.code == 200) {
state.form.json5.cards[state.form.page - 1].image = res.data.data; state.form.json5.cards[state.form.page - 1].image = res.data.data;
Toast.success("上傳成功"); showSuccessToast("上傳成功");
} else { } else {
Toast.fail("上傳失敗"); showToast.fail("上傳失敗");
} }
}, "image/jpeg"); }, "image/jpeg");
} }
@ -737,7 +737,7 @@ export default defineComponent({
state.form.json5.cards[page - 1].btns.push({ state.form.json5.cards[page - 1].btns.push({
color: "#42659a", color: "#42659a",
link: `${process.env.VUE_APP_SEND_URL}?userid=${userid}&cardid=2`, link: `${import.meta.env.VITE_APP_SEND_URL}?userid=${userid}&cardid=2`,
style: "primary", style: "primary",
text: "分享好友", text: "分享好友",
btnHeight: "md" btnHeight: "md"
@ -809,14 +809,14 @@ export default defineComponent({
imgFile.append("fileType", "IMAGE"); imgFile.append("fileType", "IMAGE");
imgFile.append("file", file.file); imgFile.append("file", file.file);
Toast.loading({ showLoadingToast({
duration: 0, duration: 0,
message: "圖片上傳中...", message: "圖片上傳中...",
forbidClick: true, forbidClick: true,
}); });
let res = await axios.post( let res = await axios.post(
`${process.env.VUE_APP_API_URL}/card/uploadfile`, `${import.meta.env.VITE_APP_API_URL}/card/uploadfile`,
imgFile, imgFile,
{} {}
); );
@ -824,9 +824,9 @@ export default defineComponent({
if (res.data.code == 200) { if (res.data.code == 200) {
state.form.json5.cards[state.form.page - 1].image = res.data.data; state.form.json5.cards[state.form.page - 1].image = res.data.data;
Toast.success("上傳成功"); showSuccessToast("上傳成功");
} else { } else {
Toast.fail("上傳失敗"); showToast.fail("上傳失敗");
} }
return; return;
@ -859,13 +859,13 @@ export default defineComponent({
const handleSubmit = async () => { const handleSubmit = async () => {
if (!validateForm(state.form.json5.cards)) { if (!validateForm(state.form.json5.cards)) {
Toast("商務卡片欄位錯誤,紅色錯誤欄位請重新檢查!!"); showToast("商務卡片欄位錯誤,紅色錯誤欄位請重新檢查!!");
return; return;
} }
let user_id = userid; let user_id = userid;
Toast.loading({ showLoadingToast({
duration: 0, duration: 0,
message: "名片上傳中...", message: "名片上傳中...",
forbidClick: true, forbidClick: true,
@ -879,9 +879,9 @@ export default defineComponent({
}); });
if (res.code === 200) { if (res.code === 200) {
store.commit("user/setCusCard", JSON.stringify(state.form)); store.commit("user/setCusCard", JSON.stringify(state.form));
Toast.success("建立成功"); showSuccessToast("建立成功");
} else { } else {
Toast.fail("建立失敗"); showToast.fail("建立失敗");
} }
router.push("/auth/getauth"); router.push("/auth/getauth");
}; };

@ -1,22 +1,3 @@
<template>
<div>
<van-nav-bar title="代客編輯商務卡片" right-text="" @click-right="$router.push('/')" />
<table id="auth-list">
<tr>
<th>授權會員</th>
<th>授權時間</th>
<th>操作</th>
</tr>
<tr v-for="v of authList" :key="v.id">
<td>{{v.user_id}}</td>
<td>{{v.auth_time}}</td>
<td @click="handleEdit(v.user_id)"></td>
</tr>
</table>
</div>
</template>
<script setup> <script setup>
import { onMounted , ref } from "vue"; import { onMounted , ref } from "vue";
@ -38,15 +19,54 @@ const handleEdit = (user_id)=>{
</script> </script>
<template>
<div class="getauth page">
<van-nav-bar class="bg-skyBlue py-1" left-arrow @click-left="$router.push('/')">
<template #title>
<h5 class="text-white mb-1"><strong>代客編輯商務卡片</strong></h5>
</template>
<template #left>
<h4><i class="fa-solid fa-angle-left text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
</van-nav-bar>
<div class="content">
<van-cell-group inset>
<table id="auth-list">
<thead>
<tr>
<th>授權會員</th>
<th>授權時間</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="v of authList" :key="v.id">
<td>{{v.user_id}}</td>
<td>{{v.auth_time}}</td>
<td @click="handleDelete(v.id)"></td>
</tr>
</tbody>
</table>
</van-cell-group>
</div>
</div>
</template>
<style src="@/assets/css/main.css"></style>
<style lang="less" scoped> <style lang="less" scoped>
#auth-list{ table#auth-list{
width: 100%; width: 100%;
td,th{ thead th{
border: 1px solid #ddd; color: #fff;
padding: 3px; background-color: #4a677d;
} }
tr:nth-child(even){ tr:nth-child(even){
background-color: #f2f2f2; background-color: #f2f2f2;
} }
th,td{
padding: 5px 10px;
}
} }
</style> </style>

File diff suppressed because it is too large Load Diff

@ -1,73 +1,38 @@
<template>
<div>
<van-nav-bar
title="自製名片"
right-text="關閉"
@click-right="$router.push('/')"
/>
<div class="recommend">
<div style="text-align: center; line-height: 24px; font-weight: bold;">
<br />
<span style="font-size: 19px; color: #cc0000;">
您沒有設定自製名片權限<br />
請點選下方立即購買按鈕<br />
開通自製名片相關服務<br />
</span>
<br />
<ul>
<li><img src="./images/0001.png" width="100%"></li>
<li><img src="./images/0002.png" width="100%"></li>
<li><img src="./images/0003.png" width="100%"></li>
<li><img src="./images/0004.png" width="100%"></li>
</ul>
<form name="" class="fbqs" style="text-align: center;">
<input type="button" value="立即購買" class="submit" style="padding: 3%; width: 50%; margin-left: auto; margin-right: auto;"
@click="router.push('/shop')"
>
</form>
</div>
</div>
<Footer/>
</div>
</template>
<script setup> <script setup>
import { useRouter} from 'vue-router' import { useRouter} from 'vue-router'
import Footer from '@/components/Footer.vue'
import Footer from '@/components/Footer'
const router = useRouter() const router = useRouter()
</script> </script>
<template>
<div class="level page">
<van-nav-bar class="bg-skyBlue py-1" left-arrow @click-left="$router.push('/')">
<template #title>
<h5 class="text-white mb-1"><strong>自製名片</strong></h5>
</template>
<template #left>
<h4><i class="fa-solid fa-angle-left text-white" :style="{opacity:0.5}"></i></h4>
</template>
</van-nav-bar>
<van-cell-group inset class="mt-3">
<div class="text-darkBlue text-center py-5">
<div class="text-tomatoRed text-center mb-4"><i class="fa-solid fa-triangle-exclamation fa-5x"></i></div>
<h5 class="text-darkBlue text-center mb-2"><strong>您沒有設定自製名片權限</strong></h5>
<h6 class="text-darkBlue text-center mb-5">請點選下方立即購買按鈕<br />開通自製名片相關服務</h6>
<van-button class="btn-darkBlue px-5" icon="balance-o" size="normal" @click="router.push('/shop')"></van-button>
</div>
</van-cell-group>
</div>
</template>
<style src="@/assets/css/main.css"></style>
<style lang="less" scoped> <style lang="less" scoped>
.recommend {
width: 100%;
padding-top: 2%;
}
.recommend ul {
width: 80%;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: 0 auto 5% auto;
}
.recommend ul li {
width: 21%;
display: flex;
flex-direction: column;
margin: 1%;
}
.recommend ul li p {
margin-top: 2%;
font-size: 15px;
color: #333;
}
.recommend ul li span {
font-size: 0.24rem;
color: #999;
padding-top: 0.15rem;
}
</style> </style>

@ -1,52 +0,0 @@
<template>
<van-nav-bar title="預覽" right-text="" @click-right="$router.push('/card/edit')" />
<div class="flex-section">
<div class="table-responsive">
<div class="chatbox">
<div id="flex" ref="flexRef"></div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onActivated, onDeactivated } from 'vue'
import { useRoute } from 'vue-router'
import { genCard1 } from '@/utils/card2'
const route = useRoute()
const flexRef = ref(null)
onActivated(() => {
flexRef.value.innerHTML = ''
let flexContent = genCard1(JSON.parse(route.params.content))
flex2html("flex", flexContent)
})
onDeactivated(() => {
})
</script>
<style lang="less" scoped>
.flex-section {
// color: white;
// z-index: 99999;
background-color: #666;
}
.chatbox {
background-color: #666;
margin-top: 10px;
padding-top: 10px;
}
.table-responsive {
width: 100%;
overflow-x: auto;
}
</style>

@ -1,7 +1,7 @@
<template> <template>
<van-nav-bar title="教學影片" right-text="" @click-right="$router.push('/card/edit')" /> <van-nav-bar title="教學影片" right-text="" @click-right="$router.push('/card')" />
<div class="yt-content"> <div class="yt-content">
<iframe width="375" height="215" src="https://www.youtube.com/embed/fjZsQ0Rh6yk" title="Utel電子名片教學" <iframe width="375" height="215" src="https://www.youtube.com/embed/94q_MPZeU6s" title="Utel電子名片教學"
frameborder="0" frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe> allowfullscreen></iframe>

@ -1,418 +1,634 @@
<template>
<div class="home" v-cloak>
<div class="my-account">
<div class="account-bg set_up">
<img src="@/assets/images/topbg.png" />
</div>
<div class="avatar_box set_up">
<img class="avater" :src="userInfo.line_picture || import('@/assets/images/user.jpg')" />
</div>
<div class="user-info">
<p class="uname set_up">UTel電子名片系統</p>
<a href="javascript:;">
<p class="umoney phone">歡迎來到會員中心</p>
</a>
</div>
<div class="set" @click="handleLogout">
<a href="javascript:void(0)">登出</a>
</div>
</div>
<div class="recommend">
<ul>
<li @click="router.push('/member')">
<p>修改資料</p>
<span>修改名片資料</span>
</li>
<li @click="goCardEdit">
<p>商務卡片</p>
<span>設計專屬名片</span>
</li>
<li @click="router.push('/shop')">
<p>立即購買</p>
<span>付費開通方案</span>
</li>
<li @click="handleShowNfc">
<p>展示二維碼</p>
<span>提供好友掃描</span>
</li>
</ul>
</div>
<dl class="dl02" v-if="userInfo">
<a href="javascript:;">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-01.png" />
<div class="left">建立日期</div>
<div class="right">{{ userInfo.create_time }}</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-02.png" />
<div class="left">會員編號</div>
<div class="right">{{ userInfo.user_id }}
<span class="cp-btn" @click="doCopyUid"></span>
</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-02.png" />
<div class="left">公司名稱</div>
<div class="right">{{ userInfo.company }}</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-03.png" />
<div class="left">姓名</div>
<div class="right">{{ userInfo.real_name }}</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-04.png" />
<div class="left">會員等級</div>
<div class="right">{{ userInfo.level_name }}</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-05.png" />
<div class="left">使用期限</div>
<div class="right">{{ overdue }}</div>
<!-- <div class="right" @click="router.push('/shop/inputsn')" v-if="!is_due">{{overdue}}<br/>點此輸入購買序號</div>
<div class="right input-sn" @click="router.push('/shop/inputsn')" v-else>,<br/>點此輸入購買序號</div> -->
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-06.png" />
<div class="left">名片連結</div>
<div class="right" style="color: #fe6867" @click="doCopy">
點擊複製您的連結
</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;">
<div class="menu" @click="$router.push('/auth/auth')">
<img class="titleImg" src="@/assets/images/icon-04.png" />
<div class="left">授權商務卡片編輯</div>
<div class="right">授權</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;" @click="$router.push('/auth/getauth')">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-04.png" />
<div class="left">代客編輯商務卡片</div>
<div class="right">編輯</div>
<div style="clear: both"></div>
</div>
</a>
<a href="javascript:;" v-if="userInfo.uniqid">
<div class="menu">
<img class="titleImg" src="@/assets/images/icon-06.png" />
<div class="left">綁定UTel淘金購會員</div>
<div class="right" style="color: #fe6867" @click="bindTggo">
點擊後前往綁定
</div>
<div style="clear: both"></div>
</div>
</a>
</dl>
<Footer />
<van-dialog v-model:show="showNfcQrcode" title="電子名片二維碼" :show-cancel-button="true" cancel-button-text=""
:show-confirm-button="false">
<div class="qrcode">
<qrcode-vue :value="userInfo.nfcurl" size="200" level="M" />
</div>
</van-dialog>
</div>
</template>
<script setup> <script setup>
import liff from "@line/liff" import moment from "moment";
import moment from 'moment' import QrcodeVue from "qrcode.vue";
import QrcodeVue from 'qrcode.vue' import { toClipboard } from "@soerenmartius/vue3-clipboard";
import { toClipboard } from '@soerenmartius/vue3-clipboard'
import { ref, computed, onBeforeMount, nextTick } from "vue"; import { ref, computed, onBeforeMount } from "vue";
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from "vue-router";
import { useStore } from 'vuex'; import { useUserStore } from '@/store/user';
import { useCardStore } from '@/store/card';
import { Toast } from 'vant' import { showToast, showSuccessToast, showConfirmDialog } from "vant";
import { Dialog } from 'vant'; import 'vant/es/toast/style';
import Footer from '@/components/Footer' import { login, bindCard, getMovie, getMarquee, bindUser } from "@/api";
import { login, bindCard } from '@/api' import noUserImg from '@/assets/images/upload.jpg'
const router = useRouter();
const route = useRoute();
const router = useRouter() const userStore = useUserStore();
const route = useRoute() const cardStore = useCardStore();
const store = useStore()
const showShare = ref(false) const showShare = ref(false);
const showNfcQrcode = ref(false);
const showQrcode = ref(false);
const showNfcQrcode = ref(false) const checked = ref(true);
const imageUrl = ref(import.meta.env.VITE_APP_BASE_URL);
const imageUrl = ref(process.env.VUE_APP_IMAGE_URL) const is_due = ref(false);
const userLevel = {
0: '基礎款',
1: '標準款',
2: '自製款',
3: '客製款'
}
const is_due = ref(false)
onBeforeMount(async () => { onBeforeMount(async () => {
const liff = window.liff;
try { try {
await liff.init({ liffId: process.env.VUE_APP_LINE_LIFF_ID }); if (!liff.isLoggedIn()) liff.login({ redirectUri: window.location.href });
if (!liff.isLoggedIn())
liff.login({ redirectUri: window.location.href });
} catch (err) { } catch (err) {
console.log(`liff.state init error ${err}`); console.log(`liff.state init error ${err}`);
Toast('登入失敗。請聯絡管理員') showToast("登入失敗。請聯絡管理員");
router.push('/login') router.push("/login");
} }
if (!sessionStorage.getItem("token")) { //
const profile = await liff.getProfile();
if (!sessionStorage.getItem('token')) { const id_token = liff.getIDToken();
const profile = await liff.getProfile()
const id_token = liff.getIDToken()
let loginRes = await login({ line_id: profile.userId, token: id_token });
let loginRes = await login({ line_id: profile.userId, token: id_token })
if (loginRes.code === 200) { if (loginRes.code === 200) {
if (route.query.act === 'openright') { if (route.query.act === "openright") {
Toast('您已經是本站會員') showToast("您已經是本站會員");
} }
sessionStorage.setItem('token', loginRes.data.token) sessionStorage.setItem("token", loginRes.data.token);
sessionStorage.setItem('uid', loginRes.data.uid) sessionStorage.setItem("uid", loginRes.data.uid);
} else if (loginRes.code === 202) { //
} else if (loginRes.code === 202) { if (route.query.act === "openright") {
if (route.query.act === 'openright') {
if (route.query.verify) { if (route.query.verify) {
// //
Dialog.confirm({ showConfirmDialog({
title: '卡片綁定', title: "卡片綁定",
message: '確認是否綁定這張卡片' message: "確認是否綁定這張卡片",
}).then(async () => { confirmButtonText: "確認",
cancelButtonText: "取消",
})
.then(async () => {
// //
let bindRes = await bindCard({ uid: loginRes.data.uid, verify: route.query.verify }) let bindRes = await bindCard({
uid: loginRes.data.uid,
verify: route.query.verify,
});
if (bindRes.code === 200) { if (bindRes.code === 200) {
Toast.success('綁定成功') showSuccessToast("綁定成功");
} else { } else {
Toast.fail('綁定失敗') showToast.fail("綁定失敗");
} }
}).catch(() => {
}) })
.catch(() => { });
} }
} }
sessionStorage.setItem('token', loginRes.data.token) sessionStorage.setItem("token", loginRes.data.token);
sessionStorage.setItem('uid', loginRes.data.uid) sessionStorage.setItem("uid", loginRes.data.uid);
} else if (loginRes.code === 201) { //
} else if (loginRes.code === 201) { if (route.query.act === "openright") { //
if (route.query.act === 'openright') { if (route.query.verify) { //
if (route.query.verify) {
router.push({ router.push({
path: '/register', path: "/register",
query: { query: {
verify: route.query.verify verify: route.query.verify,
user_id: route.query.user_id,
},
});
return;
}else if(route.query.user_id){ //lineid
//
showConfirmDialog({
title: "會員綁定",
message: "確認是否綁定會員",
confirmButtonText: "確認",
cancelButtonText: "取消",
})
.then(async () => {
//
let bindRes = await bindUser({
line_id: profile.userId,
user_id: route.query.user_id,
});
if (bindRes.code === 200) {
showSuccessToast("綁定成功");
} else {
showFailToast("綁定失敗");
return;
} }
}) })
.catch(() => { });
return
} }
} else if (route.query.aid) { } else if (route.query.aid) { //
router.push({ router.push({
path: '/register', path: "/register",
query: { query: {
aid: route.query.aid aid: route.query.aid,
} },
}) });
return return;
} else { } else {
Toast('請先註冊成為本站會員') showToast("請先註冊成為本站會員");
return router.push({ return router.push({
path: '/register', path: "/register",
query: { refer: route.query.refer } query: { refer: route.query.refer },
}) });
}
} else {
showToast("登入失敗。請聯絡管理員");
router.push("/login");
}
} }
await userStore.getUserData();
await cardStore.getCardData();
handleAD();
} else { });
Toast('登入失敗。請聯絡管理員')
router.push('/login') /**
* title : 首頁廣告
* fixed : wayne
* date : 2023/10/26
*/
const noticeData = ref([]);
const adData = ref({});
const noticeClick = (num) => {
let url = noticeData.value[num].ad_link;
window.open(url, "_blank");
};
const handleAD = async () => {
if (userInfo.value.status === 0) {
let res;
res = await getMarquee();
if (res.code === 200) {
noticeData.value = res.data;
}
res = await getMovie();
if (res.code === 200) {
// res.dataObject
if (Object.keys(res.data).length !== 0) {
adData.value = res.data;
popShow.value = true;
}
} }
} }
};
store.dispatch('user/getUserInfo') const popShow = ref(false);
const modalClose = ref(false);
// const closeShow = () => {
nextTick(() => { modalClose.value = true;
};
// if(userInfo.value.level===0 && userInfo.value.nc_type===0){ // 使computed, userInfo.value.is_send_ad
// Toast('') // const adSwitchStatus = ref(Boolean(userInfo.value.is_send_ad));
// return router.push('/shop/inputsn') const adSwitchStatus = computed(() => {
// } return Boolean(userInfo.value.is_send_ad);
}) });
})
const onUpdateValue = (newValue) => {
showConfirmDialog({
title: "提醒確認",
message: "是否切換開關?",
confirmButtonText: "確認",
cancelButtonText: "取消",
}).then(() => {
let res = userStore.setSendWithAd(newValue)
console.log('aaa',userInfo.value.is_send_ad)
}).catch(() => {
// on cancel
});
};
const userInfo = computed(() => { const userInfo = computed(() => {
return store.state.user.userInfo return userStore.userData;
}) });
const nfcurl = computed(() => { const nfcurl = computed(() => {
return encodeURI(store.state.user.userInfo.ufcurl) return encodeURI(userStore.userData.ufcurl);
}) });
const overdue = computed(() => { const overdue = computed(() => {
if (store.state.user.userInfo.overdue_time > 0) { if (userStore.userData.overdue_time > 0) {
return moment.unix(store.state.user.userInfo.overdue_time).format('YYYY-MM-DD') return moment
.unix(userStore.userData.overdue_time)
.format("YYYY-MM-DD");
} else { } else {
return '無期限' return "無期限";
} }
}) });
const goCardEdit = () => { const goCardEdit = () => {
if (userInfo.value.nc_type < 2) { // if (userInfo.value.nc_type < 2) {
router.push('/card/notice') if (userInfo.value.level < 2) {
router.push("/card/notice");
} else { } else {
router.push('/card/edit') router.push("/card");
}
} }
};
const onSelect = (option) => { const onSelect = (option) => {
Toast(option.name); showToast(option.name);
showShare.value = false; showShare.value = false;
}; };
const handleShow = () => {
showQrcode.value = true;
};
const handleShowNfc = () => { const handleShowNfc = () => {
showNfcQrcode.value = true showNfcQrcode.value = true;
} };
const doCopy = () => { const doCopy = () => {
toClipboard(userInfo.value.nfcurl) toClipboard(userInfo.value.nfcurl);
Toast('已放入剪貼簿') showToast("已放入剪貼簿");
} };
const doCopyUid = () => { const doCopyUid = () => {
toClipboard(userInfo.value.user_id) toClipboard(userInfo.value.user_id);
Toast('已放入剪貼簿') showToast("已放入剪貼簿");
} };
const doShare = () => {
toClipboard(`https://liff.line.me/${import.meta.env.VITE_APP_LINE_LIFF_ID}/?aid=${userInfo.value.user_id}`)
showToast("已放入剪貼簿");
};
const bindTggo = () => { const bindTggo = () => {
console.log(userInfo.value) if (userInfo.value.uniqid) {
let url = `https://www.tggo.com.tw/u.cgi?&mnm=mybinding&ncode=${userInfo.value.uniqid}&name=${userInfo.value.real_name}&openExternalBrowser=1`; let url = `https://www.tggo.com.tw/u.cgi?&mnm=mybinding&ncode=${userInfo.value.uniqid}&name=${userInfo.value.real_name}&openExternalBrowser=1`;
window.open(url, "_blank");
window.open(url, '_blank'); return;
} }
showToast('您的帳號尚未綁定感應卡');
};
const handleLogout = () => { const handleLogout = () => {
if (liff.isLoggedIn()) { if (liff.isLoggedIn()) {
liff.logout(); liff.logout();
} }
sessionStorage.removeItem('token') sessionStorage.removeItem("token");
sessionStorage.removeItem('uid') sessionStorage.removeItem("uid");
router.push('/login') router.push("/login");
} };
</script> </script>
<style src="@/assets/css/style.css"></style> <template>
<div class="home page" v-cloak>
<van-nav-bar class="bg-darkBlue py-3">
<template #title>
<h4 class="text-white mb-1"><strong>UTEL電子名片系統</strong></h4>
<a href="javascript:;">
<h5 class="text-gray">歡迎來到會員中心</h5>
</a>
</template>
<template #left>
<div class="btn btn-sm text-skyBlue" @click="handleLogout">
<h4><i class="fa-solid fa-arrow-right-to-bracket"></i></h4>
</div>
</template>
<template #right>
<div class="btn btn-sm text-skyBlue" @click="router.push('/member')">
<h4><i class="fa-solid fa-bars"></i></h4>
</div>
</template>
</van-nav-bar>
<!-- START: 跑馬燈 -->
<template v-if="userInfo.status === 0">
<van-notice-bar color="#ffffff" background="#e05338" left-icon="volume" mode="link" :scrollable="true">
<van-swipe class="notice-swipe" :touchable="false" :show-indicators="false">
<van-swipe-item v-for="(item, key, index) in noticeData" :key="index" @click="noticeClick(key)">
{{ item.ad_title }}
</van-swipe-item>
</van-swipe>
</van-notice-bar>
</template>
<!-- END: 跑馬燈 -->
<div class="my-account">
<div class="avatar">
<div class="left">
<div class="imgCnt shadow-sm">
<img :src="userInfo.avatar || noUserImg" />
</div>
<div class="info">
<h3 class="name">{{ userInfo.real_name }}</h3>
<h5 class="conpany">{{ userInfo.company }}</h5>
</div>
</div>
<!-- <div class="right">
<div class="btn btn-sm text-darkBlue" @click="doShare">
<h4><i class="fa-solid fa-clone"></i></h4>
</div>
</div> -->
</div>
<div class="recommend">
<div class="btn btn-outline-lightBlue shadow-sm" @click="router.push('/shop')">
<div class="img"><i class="fa-solid fa-cart-arrow-down"></i></div>
<div class="text">立即開通</div>
</div>
<div class="btn btn-outline-lightBlue shadow-sm" @click="goCardEdit">
<div class="img"><i class="fa-solid fa-id-card"></i></div>
<div class="text">商務卡片</div>
</div>
<div class="btn btn-outline-lightBlue shadow-sm" @click="router.push('/address')">
<div class="img"><i class="fa-solid fa-address-book"></i></div>
<div class="text">通訊錄</div>
</div>
</div>
</div>
<!-- <div class="bwtFlex px-3 mb-2">
<h5 class="font-weight-bold text-darkBlue">會員資料</h5>
<a href="javascript:;" @click="router.push('/member')">
<h5><i class="fa-solid fa-sliders text-darkBlue"></i></h5>
</a>
</div> -->
<div class="content" v-if="userInfo">
<van-cell-group inset>
<van-field :model-value="userInfo.create_time" input-align="right" readonly>
<template #label><i class="fa-regular fa-fw fa-calendar-days"></i> 建立日期</template>
</van-field>
<van-field :model-value="userInfo.user_id" input-align="right" readonly>
<template #label><i class="fa-solid fa-fw fa-fingerprint"></i> 會員編號</template>
<template #button>
<van-button size="small" @click="doCopyUid">
<i class="fa-regular fa-copy"></i>
</van-button>
</template>
</van-field>
<van-field :model-value="userInfo.level_name" input-align="right" readonly>
<template #label><i class="fa-solid fa-fw fa-layer-group"></i> 會員等級</template>
</van-field>
<van-field :model-value="overdue" input-align="right" readonly>
<template #label><i class="fa-regular fa-fw fa-calendar-check"></i> 使用期限</template>
</van-field>
<van-field input-align="right" class="longText" readonly>
<template #label><i class="fa-solid fa-fw fa-handshake-angle"></i> 分享加入</template>
<template #button>
<van-button size="small" class="btn-outline-skyBlue mr-1" @click="handleShow"><i
class="fa-solid fa-qrcode"></i> QRcode
</van-button>
<van-button size="small" class="btn-outline-skyBlue" @click="doShare"><i class="fa-regular fa-copy"></i> 複製連結
</van-button>
</template>
</van-field>
<van-field input-align="right" class="longText" readonly>
<template #label><i class="fa-solid fa-fw fa-chess-board"></i> NFC名片</template>
<template #button>
<van-button size="small" class="btn-outline-skyBlue mr-1" @click="handleShowNfc"><i
class="fa-solid fa-qrcode"></i> QRcode
</van-button>
<van-button size="small" class="btn-outline-skyBlue" @click="doCopy"><i class="fa-regular fa-copy"></i> 複製連結
</van-button>
</template>
</van-field>
</van-cell-group>
<van-cell-group inset>
<van-field :model-value="userInfo.title" input-align="right" readonly>
<template #label><i class="fa-regular fa-fw fa-building"></i> 職稱</template>
</van-field>
<van-field :model-value="userInfo.phone" input-align="right" readonly>
<template #label><i class="fa-solid fa-fw fa-mobile-retro"></i> 手機</template>
</van-field>
<van-field :model-value="userInfo.tel" input-align="right" readonly>
<template #label><i class="fa-solid fa-fw fa-phone"></i> 市話</template>
</van-field>
<van-field :model-value="userInfo.email" input-align="right" readonly>
<template #label><i class="fa-regular fa-fw fa-envelope"></i> Email</template>
</van-field>
<van-field :model-value="userInfo.address" input-align="right" readonly>
<template #label><i class="fa-solid fa-fw fa-location-dot"></i> 住址</template>
</van-field>
</van-cell-group>
<van-cell-group inset>
<van-field input-align="right" class="longText" readonly>
<template #label><i class="fa-solid fa-fw fa-user-tie"></i> 授權商務卡片編輯</template>
<template #button>
<van-button size="small" @click="$router.push('/auth/auth')">
授權
</van-button>
</template>
</van-field>
<van-field input-align="right" class="longText" readonly>
<template #label><i class="fa-regular fa-fw fa-handshake"></i> 代客編輯商務卡片</template>
<template #button>
<van-button size="small" @click="$router.push('/auth/getauth')">
編輯
</van-button>
</template>
</van-field>
<van-field input-align="right" class="longText" readonly>
<template #label><i class="fa-solid fa-fw fa-award"></i> 綁定UTel淘金購會員</template>
<template #button>
<van-button size="small" @click="bindTggo">
點擊後前往綁定
</van-button>
</template>
</van-field>
<van-field input-align="right" class="longText" readonly>
<template #label><i class="fa-regular fa-fw fa-paper-plane"></i> 發送名片帶廣告</template>
<template #input>
<van-switch v-model="adSwitchStatus" @update:model-value="onUpdateValue" size="18px" active-color="#345068"
inactive-color="#888888" />
</template>
</van-field>
</van-cell-group>
<van-sticky position="bottom">
<div class="bottomBtnCnt">
<van-button size="normal" block class="bg-darkBlue text-white border-0" @click="router.push('/send')">
<h5><i class="fa-regular fa-fw fa-paper-plane"></i> 發送名片</h5>
</van-button>
</div>
</van-sticky>
</div>
<van-dialog v-model:show="showQrcode" title="會員加入分享" :show-cancel-button="true" cancel-button-text=""
:show-confirm-button="false">
<div class="qrcode text-center pt-3">
<qrcode-vue :value="userInfo.referurl" :size="200" level="M" />
</div>
</van-dialog>
<van-dialog v-model:show="showNfcQrcode" title="NFC名片分享" :show-cancel-button="true" cancel-button-text=""
:show-confirm-button="false">
<div class="qrcode text-center pt-3">
<qrcode-vue :value="userInfo.nfcurl" :size="200" level="M" />
</div>
</van-dialog>
<van-overlay :show="popShow" z-index="1000" :style="{ background: 'rgba(0, 0, 0, .85)' }">
<div class="wrapper" @click.stop>
<div class="clip">
<van-icon :style="{ display: 'none', marginRight: '5px' }" @click="popShow = false"
:class="{ 'd-block': modalClose }" name="cross" size="15" />
<van-count-down :style="{ color: '#fff' }" @finish="closeShow" :auto-start="true" :time="adData.play_sec * 1000"
format="ss 秒" />
</div>
<div class="top">
<iframe width="100%" height="100%" :src="imageUrl + adData.ad_movie" title="YouTube video player"
autoplay="true" frameborder="0" controls="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen></iframe>
</div>
<div class="bottom">
<h5 class="title">{{ adData.ad_title }}</h5>
<h6 class="desc ellipsis e3">{{ adData.ad_desc }}</h6>
<van-button type="light" :url="adData.ad_link" block v-if="adData.ad_link">
<i class="fa-solid fa-fw fa-link"></i> 前往連結
</van-button>
</div>
</div>
</van-overlay>
</div>
</template>
<style src="@/assets/css/main.css"></style>
<style lang="less" scoped> <style lang="less" scoped>
[ v-cloak] { .home {
display: none; .wrapper {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100%;
.clip {
position: absolute;
display: flex;
align-items: center;
color: #ffffff;
background-color: rgba(#000000, 0.8);
top: 5px;
right: 5px;
margin-left: auto;
padding: 10px;
cursor: pointer;
z-index: 1005;
}
.top {
position: relative;
display: flex;
align-items: center;
width: 100%;
flex: 1 0 0;
} }
.recommend { .bottom {
position: relative;
width: 100%; width: 100%;
padding-top: 2%; flex: 0 0 auto;
padding: 15px;
.title {
color: #ffffff;
font-weight: bold;
margin-bottom: 15px;
} }
.recommend ul { .desc {
color: #ffffff;
margin-bottom: 30px;
}
}
}
.my-account {
position: relative;
width: 100%; width: 100%;
padding: 20px 25px;
.avatar {
display: flex; display: flex;
flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
} align-items: center;
.recommend ul li { .left {
box-sizing: content-box;
width: 44%;
height: 50px;
padding: 2%;
display: flex; display: flex;
flex-direction: column; align-items: center;
margin: 1%; flex: 1 0 0;
-webkit-box-shadow: 0 0 2px #fdaf00;
-moz-box-shadow: 0 0 2px #fdaf00; .imgCnt {
box-shadow: 0 0 2px #fdaf00; width: 80px;
height: 80px;
min-width: 80px;
border-radius: 50%;
border: 2px #fff solid;
overflow: hidden;
margin-right: 15px;
img {
width: 100%;
height: 100%;
object-fit: cover;
} }
.recommend ul li p {
margin-top: 2%;
font-size: 15px;
color: #333;
} }
.recommend ul li span { .info {
font-size: 14px !important; .name {
color: #999 !important; font-weight: bold;
padding-top: 0.15rem !important; color: #303a47;
} }
.recommend ul li:nth-child(1) { .conpany {
background: url(~@/assets/images/icon-001.png) right 0.3rem center no-repeat #fff !important; margin-top: 5px;
background-size: 30px !important;
} }
.recommend ul li:nth-child(2) {
background: url(~@/assets/images/icon-002.png) right 0.3rem center no-repeat #fff !important;
background-size: 30px !important;
} }
.recommend ul li:nth-child(3) {
background: url(~@/assets/images/icon-003.png) right 0.3rem center no-repeat #fff !important;
background-size: 30px !important;
} }
.recommend ul li:nth-child(4) { .right {
background: url(~@/assets/images/icon-004.png) right 0.3rem center no-repeat #fff !important; flex: 0 0 auto;
background-size: 30px !important;
} }
.qrcode {
text-align: center;
} }
.input-sn { .recommend {
color: red !important; display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 0 10px;
.btn {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 30%;
height: 100px;
background-color: #fff;
border-radius: 0;
.img {
font-size: 35px;
line-height: 45px;
color: #345068;
} }
.cp-btn { .text {
border: #999 1px solid; font-size: 16px;
padding: 2px; font-weight: bold;
color: rgb(254, 104, 103); color: #345068;
}
}
}
}
} }
</style> </style>

@ -0,0 +1,104 @@
<script setup>
import { onBeforeMount } from "vue";
import { showToast } from 'vant'
import { useRouter, useRoute } from 'vue-router';
const route = useRoute();
const router = useRouter();
import { login, bindCard } from "@/api";
const liff = window.liff;
onBeforeMount(async () => {
try {
if (!liff.isLoggedIn()) liff.login({ redirectUri: window.location.href });
} catch (err) {
console.log(`liff.state init error ${err}`);
showToast("登入失敗。請聯絡管理員");
return router.push("/login");
}
if (!sessionStorage.getItem("token")) { //
const profile = await liff.getProfile();
const id_token = liff.getIDToken();
let loginRes = await login({ line_id: profile.userId, token: id_token });
if (loginRes.code === 200) {
if (route.query.act === "openright") {
showToast("您已經是本站會員");
}
sessionStorage.setItem("token", loginRes.data.token);
sessionStorage.setItem("uid", loginRes.data.uid);
} else if (loginRes.code === 202) { //
if (route.query.act === "openright") {
if (route.query.verify) {
//
Dialog.confirm({
title: "卡片綁定",
message: "確認是否綁定這張卡片",
})
.then(async () => {
//
let bindRes = await bindCard({
uid: loginRes.data.uid,
verify: route.query.verify,
});
if (bindRes.code === 200) {
showSuccessToast("綁定成功");
} else {
showToast.fail("綁定失敗");
}
})
.catch(() => { });
}
}
sessionStorage.setItem("token", loginRes.data.token);
sessionStorage.setItem("uid", loginRes.data.uid);
} else if (loginRes.code === 201) { //
if (route.query.act === "openright") { //
if (route.query.verify || route.query.user_id) {
return router.push({
path: "/register",
query: {
verify: route.query.verify,
user_id: route.query.user_id,
},
});
}
} else if (route.query.aid) { //
return router.push({
path: "/register",
query: {
aid: route.query.aid,
},
});
} else {
showToast("請先註冊成為本站會員");
return router.push({
path: "/register",
query: { refer: route.query.refer },
});
}
} else {
showToast("登入失敗。請聯絡管理員");
return router.push("/login");
}
}
// redirect
if (sessionStorage.getItem("redirect")) {
router.push(sessionStorage.getItem("redirect"));
sessionStorage.removeItem("redirect");
return;
} else {
return router.push("/");
}
});
</script>

@ -19,7 +19,7 @@ import store from '@/store'
import router from '@/router' import router from '@/router'
import { Toast } from 'vant' import { showToast } from 'vant'
import { login } from '@/api' import { login } from '@/api'
@ -50,14 +50,14 @@ const handleLogin1 = async()=>{
// console.log('data',loginRes.data) // console.log('data',loginRes.data)
sessionStorage.setItem('token',loginRes.data.token) sessionStorage.setItem('token',loginRes.data.token)
sessionStorage.setItem('uid',loginRes.data.uid) sessionStorage.setItem('uid',loginRes.data.uid)
Toast('登入成功') showToast('登入成功')
// return router.push('/') // return router.push('/')
}else if(loginRes.code===201){ }else if(loginRes.code===201){
Toast('請先註冊成為本站會員') showToast('請先註冊成為本站會員')
return router.push('/register') return router.push('/register')
} }
Toast('登入失敗。請聯絡管理員') showToast('登入失敗。請聯絡管理員')
// console.log(loginRes) // console.log(loginRes)
// let checkLine = await checkLineId(profile.userId) // let checkLine = await checkLineId(profile.userId)

@ -0,0 +1,169 @@
<script setup>
import { ref, onMounted } from 'vue';
import { searchConnection,addUserFavi } from "@/api";
const tab2list = ref([]);
const tab2Loading = ref(false);
const tab2Finished = ref(false);
const tab2TodoLists = ref([]);
const tab2AddFriend = ref([]);
const loading = ref(false);
const finished = ref(false);
const form = ref({
user_id: 1,
real_name: '王小明',
avatar: '/src/assets/images/tp/tp_1.jpg',
note: '我是王小明',
supply: '我能分享的資源',
demand: '我需要的資源',
});
onMounted(async () => {
let res = await searchConnection();
console.log(res);
if(res.code===200){
tab2list.value = res.data;
}
res = await addUserFavi({uf_user_id:form.value.user_id});
// console.log(res);
if(res.code===200){
tab2AddFriend.value = res.data;
}
});
const tab2result = ref('');
const tab2showPicker = ref(false);
const tab2columns = [
{ text: '臺北', value: 'Taipei' },
{ text: '桃園', value: 'Taoyuan' },
{ text: '臺中', value: 'Taichung' },
{ text: '彰化', value: 'Changhua' },
{ text: '高雄', value: 'Kaohsiung' },
];
const tab2ListonLoad = () => {
//
// setTimeout ajax
// setTimeout(() => {
// for (let i = 0; i < 10; i++) {
// tab2list.value.push(tab2list.value.length + 1);
// }
// //
// tab2Loading.value = false;
// //
// if (tab2list.value.length >= 40) {
// tab2Finished.value = true;
// }
// }, 1000);
};
const tab2OnConfirm = ({ selectedOptions }) => {
tab2result.value = selectedOptions[0]?.text;
tab2showPicker.value = false;
};
const tab2searchValue = ref('');
const tab2OnSearch = () => {
// tab2TodoLists = tab2list.filter(tab2searchValue);
// console.log(tab2TodoLists)
};
</script>
<template>
<div class="content cnt2">
<van-cell-group inset>
<van-row align="center">
<van-col span="8">
<van-field
v-model="tab2result"
is-link
readonly
name="picker"
:border="false"
placeholder="縣市"
@click="tab2showPicker = true"
/>
<van-popup v-model:show="tab2showPicker" position="bottom">
<van-picker
:columns="tab2columns"
@confirm="tab2OnConfirm"
@cancel="tab2showPicker = false"
/>
</van-popup>
</van-col>
<van-col span="16">
<van-search
v-model="tab2searchValue"
placeholder="請輸入搜尋關鍵字"
@search="tab2OnSearch"
/>
</van-col>
</van-row>
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="沒有更多了"
@load="tab2ListonLoad"
class="accordion"
id="accordion"
>
<!-- <van-cell v-for="item in list" :key="item" :title="item" > -->
<!-- <van-cell v-for="item in tab2list" :key="item" :title="item">
<template #title>
<div class="list-item">
<div class="avatar"><img :src="item.avatar"></div>
<div class="text">
<h5 class="name ellipsis">{{item.real_name}}</h5>
<div class="desc ellipsis">@{{item.note}}</div>
</div>
</div>
</template>
<template #value>
<van-button size="normal" class="border-0"><h5><i class="fa-solid fa-layer-group text-darkBlue"></i></h5></van-button>
<van-button size="normal" class="border-0"><h5><i class="fa-solid fa-comment-medical text-darkBlue"></i></h5></van-button>
</template>
</van-cell> -->
<div class="list-item" v-for="(item, index) in tab2list" :key="index">
<div class="left">
<div class="avatar"><img :src="item.avatar"></div>
<div class="text">
<h5 class="name ellipsis">{{item.real_name}}</h5>
<div class="desc ellipsis">@{{item.note}}</div>
</div>
</div>
<div class="right">
<van-button size="normal" class="border-0" data-toggle="collapse" :href="`#c${index}`" role="button" aria-expanded="false" :aria-controls="`c${index}`">
<h5><i class="fa-solid fa-layer-group text-darkBlue"></i></h5>
</van-button>
<van-button size="normal" class="border-0"><h5><i class="fa-solid fa-comment-medical text-darkBlue"></i></h5></van-button>
</div>
<div class="bottom collapse" :id="`c${index}`" data-parent="#accordion">
<h6 class="text-darkBlue"><strong>我能分享的資源</strong></h6>
<div class="desc">{{item.supply}}</div>
<div class="url py-2">網址<a href=""></a></div>
<hr/>
<h6 class="text-darkBlue"><strong>我需要的資源</strong></h6>
<div class="desc">{{item.demand}}</div>
</div>
</div>
</van-list>
</van-cell-group>
</div>
</template>
<style scoped>
</style>

@ -0,0 +1,196 @@
<script setup>
import { ref, onMounted } from "vue";
import { getUserInfo, updateCard } from "@/api";
const form = ref({ addon: [] });
// if (userRes.data.nfc_addon && (userRes.data.nfc_addon.length > 0)) {
// form.value.addon = JSON.parse(userRes.data.nfc_addon)
// }
onMounted(async () => {
let userRes = await getUserInfo();
if (userRes.code === 200) {
form.value = userRes.data;
}
});
const onAddBtn = () => {
if (form.value.addon) {
form.value.addon.push({ icon: "", name: "", link: "" });
} else {
form.value.addon = [{ icon: "", name: "", link: "" }];
}
};
const onDelBtn = (index) => {
form.value.addon.splice(index, 1);
};
const onMoveBtn = (type, index) => {
if (type === 0) {
if (index !== 0) {
[form.value.addon[index], form.value.addon[index - 1]] = [
form.value.addon[index - 1],
form.value.addon[index],
];
}
} else {
if (index + 1 !== form.value.addon.length) {
[form.value.addon[index + 1], form.value.addon[index]] = [
form.value.addon[index],
form.value.addon[index + 1],
];
}
}
};
const onSubmit = () => {
console.log(form.value);
};
</script>
<template>
<div class="content cnt1">
<van-cell-group inset>
<van-form @submit="onSubmit">
<van-field
v-model="form.nfcurl"
label="個人網頁"
name=""
placeholder="請輸入您的個人網頁"
/>
<van-field
v-model="form.line"
label="Line"
name=""
placeholder="請輸入您的Line ID"
/>
<van-field
v-model="form.facebook"
label="Facebook"
name=""
placeholder="請輸入您的Facebook"
/>
<van-field
v-model="form.ig"
label="IG"
name=""
placeholder="請輸入您的IG"
/>
<van-field
v-model="form.youTube"
label="YouTube"
name=""
placeholder="請輸入您的YouTube"
/>
<van-field
v-model="form.wechat"
label="WeChat"
name=""
placeholder="請輸入您的WeChat"
/>
<div class="px-5 py-4">
<van-button block class="btn-darkBlue" native-type="submit">
<h6>確認修改</h6>
</van-button>
</div>
</van-form>
</van-cell-group>
<van-cell-group inset>
<van-form @submit="onSubmit">
<van-cell class="bg-lightPink">
<template #title>
<h6 class="text-darkBlue"><strong>相關連結</strong></h6>
</template>
<template #value>
<van-button
size="small"
class="btn-outline-darkBlue"
@click="onAddBtn"
>
<h6>新增連結</h6>
</van-button>
</template>
</van-cell>
<van-field v-for="(item, idx) in form.addon" :key="idx">
<template #label>
<van-field
v-model="item.name"
name=""
maxlength="15"
placeholder="請輸入您的連結名稱"
:rules="[{ required: true, message: '連結名稱必填' }]"
/>
</template>
<template #input>
<van-field
v-model="item.link"
name=""
placeholder="請輸入您的按鈕連結"
:rules="[{ required: true, message: '按鈕連結必填' }]"
/>
</template>
<template #button>
<van-button
size="small"
class="ml-1 btn-tomatoRed"
icon="delete-o"
hairline
@click="onDelBtn(idx)"
></van-button>
<van-button
size="small"
class="ml-1 btn-skyBlue"
icon="arrow-up"
hairline
@click="onMoveBtn(0, idx)"
></van-button>
<van-button
size="small"
class="ml-1 btn-skyBlue"
icon="arrow-down"
plain
hairline
@click="onMoveBtn(1, idx)"
></van-button>
</template>
</van-field>
<!-- <van-swipe-cell v-for="(item,idx) in form.addon" :key="idx">
<template #left>
<van-button type="danger" icon="delete-o" plain hairline @click="onDelBtn(idx)"></van-button>
</template>
<van-field
v-model="item.name"
name=""
placeholder="請輸入您的連結名稱"
:rules="[{ required: true, message: '連結名稱必填' }]"
/>
<van-field
v-model="item.link"
name=""
placeholder="請輸入您的按鈕連結"
:rules="[{ pattern: /^([\w\.\-]){1,64}\@([\w\.\-]){1,64}/ , message: 'Email格式錯誤' }]"
/>
<template #right>
<van-button type="primary" icon="arrow-up" plain hairline @click="onMoveBtn(0,idx)"></van-button>
<van-button type="primary" icon="arrow-down" plain hairline @click="onMoveBtn(1,idx)"></van-button>
</template>
</van-swipe-cell> -->
<div class="px-5 py-4">
<van-button block class="btn-darkBlue" native-type="submit">
<h6>確認修改</h6>
</van-button>
</div>
</van-form>
</van-cell-group>
</div>
</template>
<style scoped></style>

@ -0,0 +1,70 @@
<script setup>
import { ref, onMounted } from 'vue';
import { setUserNfcTpl } from "@/api";
const tab3list = ref([]);
onMounted(async () => {
let res = await setUserNfcTpl();
console.log(res);
if(res.code===200){
tab3list.value = res.data;
}
});
const onSubmit = () => {
}
</script>
<template>
<div class="content cnt3">
<van-cell-group inset>
<van-form @submit="onSubmit">
<van-cell class="text-center bg-lightPink py-3">
<template #title>
<h6 class="text-darkBlue"><strong>感應式版型切換</strong></h6>
</template>
</van-cell>
<div class="text-center bg-dark px-5 pt-3">
<van-image
width="100%"
height="500"
position="top"
fit="cover"
src="/src/assets/images/tp/tp_1.jpg"
/>
</div>
<div class="d-flex justify-content-center py-3">
<van-button class="btn-tomatoRed px-5 mr-2">
預覽
</van-button>
<van-button class="btn-darkBlue px-5" native-type="submit">
確認修改
</van-button>
</div>
</van-form>
</van-cell-group>
<van-cell-group inset>
<van-row>
<van-col span="12" v-for="(item, index) in tab3list" :key="index">
<div class="imgBtn">
<div class="imgCnt">{{ item }}
<van-image
src="/src/assets/images/tp/tp_1.jpg"
/>
</div>
</div>
</van-col>
</van-row>
</van-cell-group>
</div>
</template>
<style scoped>
</style>

@ -0,0 +1,435 @@
<script setup>
import { ref, onMounted } from "vue";
import { Cropper } from "vue-advanced-cropper";
import "vue-advanced-cropper/dist/style.css";
import { getUserInfo, updateCard } from "@/api";
const crop = ref({
show: false,
img: null,
});
const fileList = ref([]);
const myCrop = ref(null);
const genderChecked = ref();
const showPicker = ref(false);
const showWorkPicker = ref(false);
const columns = [
{ text: "杭州", value: "Hangzhou" },
{ text: "宁波", value: "Ningbo" },
{ text: "温州", value: "Wenzhou" },
{ text: "绍兴", value: "Shaoxing" },
{ text: "湖州", value: "Huzhou" },
];
const columns2 = [
{ text: "杭州", value: "Hangzhou" },
{ text: "宁波", value: "Ningbo" },
{ text: "温州", value: "Wenzhou" },
{ text: "绍兴", value: "Shaoxing" },
{ text: "湖州", value: "Huzhou" },
];
const form = ref({ addon: [] });
onMounted(async () => {
let userRes = await getUserInfo();
if (userRes.code === 200) {
form.value = userRes.data;
}
});
const validatorUrl = (val) => {
if (val.length > 0) {
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val);
} else {
return true;
}
};
const validatorTel = (val) => {
if (val.length > 0) {
return /(\d{2,3}-?|\(\d{2,3}\))\d{3,4}-?\d{4}/.test(val);
} else {
return true;
}
};
const afterRead = async (file, name) => {
crop.value.show = true;
const ofile = file.file;
crop.value.img = URL.createObjectURL(ofile);
// crop.value.img = ofile
return;
};
const onCrop = () => {
const { canvas } = myCrop.value.getResult();
if (canvas) {
const imgFile = new FormData();
canvas.toBlob(async (blob) => {
let ufile = new File([blob], "image.jpg");
imgFile.append("user_id", form.value.user_id);
imgFile.append("fileType", "IMAGE");
imgFile.append("file", ufile);
crop.value.show = false;
showLoadingToast({
duration: 0,
message: "圖片上傳中...",
forbidClick: true,
});
let res = await axios.post(
`${import.meta.env.VITE_APP_API_URL}/user/uploadAvatar`,
imgFile,
{}
);
if (res.data.code == 200) {
form.value.avatar = res.data.data;
showSuccessToast("上傳成功");
} else {
showToast.fail("上傳失敗");
}
}, "image/jpeg");
}
return;
};
const searchChecked = ref(true);
const searchOnUpdateValue = (newValue) => {
showConfirmDialog({
title: "提醒",
message: "是否切換開關?",
}).then(() => {
searchChecked.value = newValue;
});
};
const onSubmit = async () => {
console.log(form.value);
return;
showLoadingToast({
duration: 0,
message: "資料更新中...",
forbidClick: true,
});
let res = await updateCard(form.value);
if (res.code === 200) {
showSuccessToast("更新成功");
store.commit("user/setUserInfo", form.value);
router.push("/member");
} else {
showToast.fail("更新失敗");
}
};
const activeCollapse = ref("1");
</script>
<template>
<div class="content cnt0">
<van-cell-group inset>
<van-form @submit="onSubmit">
<div class="text-center p-4">
<van-uploader
:after-read="afterRead"
:max-count="1"
name="averter"
class="mb-4"
>
<div class="upload-main">
<img
class="upload-img"
:src="form.avatar"
alt=""
v-if="form.avatar"
/>
<img
class="upload-img"
src="@/assets/images/upload.jpg"
alt=""
v-else
/>
<div class="ml-3">
<p class="text-skyBlue mb-2">上傳圖片預設為Line頭像</p>
<van-button class="btn-darkBlue" icon="plus" block size="small"
>上傳檔案</van-button
>
</div>
</div>
</van-uploader>
<van-field
v-model="form.mark"
rows="3"
type="textarea"
maxlength="200"
placeholder="請輸入200字以內的簡介"
show-word-limit
:style="{ border: '1px #e3e3e3 solid', borderRadius: '6px' }"
/>
</div>
<van-field
v-model="form.real_name"
label="姓名"
name="pattern"
placeholder="請輸入您的姓名"
:rules="[{ required: true, message: '姓名為必填' }]"
/>
<van-field
v-model="form.company"
label="公司名稱"
name=""
placeholder="請輸入您的公司名稱"
:rules="[{ required: true, message: '公司名稱必填' }]"
/>
<van-field
v-model="form.title"
label="職稱"
name=""
placeholder="請輸入您的職稱"
/>
<van-field
v-model="form.phone"
label="手機"
name=""
type="tel"
placeholder="Ex. 0900000001 不要有空格"
:rules="[
{ required: true, message: '手機號必填' },
{ pattern: /\d{10}/, message: '手機號格式錯誤' },
]"
/>
<van-field
v-model="form.tel"
label="市話"
name=""
type="tel"
placeholder="請輸入您的市話"
:rules="[
{
validator: validatorTel,
message: '市話格式不正確,Ex. 02xxxx or 02-xxxx',
},
]"
/>
<van-field
v-model="form.email"
label="Email"
name=""
placeholder="請輸入您的Email"
:rules="[
{ required: true, message: 'Email必填' },
{
pattern: /^([\w\.\-]){1,64}\@([\w\.\-]){1,64}/,
message: 'Email格式錯誤',
},
]"
/>
<van-field
v-model="form.address"
label="住址"
name=""
placeholder="請輸入您的地址"
/>
<van-field
v-model="form.age"
label="年齡"
name=""
placeholder="請輸入您的年齡"
/>
<van-field name="radio" label="性別">
<template #input>
<van-radio-group
v-model="form.sex"
direction="horizontal"
checked-color="#345068"
>
<van-radio :name="0"></van-radio>
<van-radio :name="1"></van-radio>
<van-radio :name="2">未知</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
v-model="form.area"
is-link
readonly
name="picker"
label="區域"
placeholder="請選擇縣市區域"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker
:columns="columns"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
<van-field
v-model="form.area"
is-link
readonly
name="picker2"
label="工作性質"
placeholder="請選擇工作性質"
@click="showWorkPicker = true"
/>
<van-popup v-model:show="showWorkPicker" position="bottom">
<van-picker
:columns="columns2"
@confirm="onConfirm"
@cancel="showWorkPicker = false"
/>
</van-popup>
<van-field readonly>
<template #label>是否公開<br />資料搜尋</template>
<template #input>
<van-switch
v-model="searchChecked"
@update:model-value="searchOnUpdateValue"
size="18px"
active-color="#345068"
inactive-color="#888888"
/>
</template>
</van-field>
<div class="p-5">
<van-button block class="btn-darkBlue" native-type="submit">
確認修改
</van-button>
</div>
</van-form>
</van-cell-group>
<van-cell-group inset>
<van-form @submit="onSubmit">
<van-cell class="text-center bg-lightPink py-3">
<template #title>
<h6 class="text-darkBlue"><strong>人脈資訊</strong></h6>
</template>
</van-cell>
<van-field
v-model="form.note"
name="pattern"
placeholder="請輸入簡短的自我介紹"
label-align="top"
>
<template #label>
<i class="fa-regular fa-gem text-darkBlue"></i> 一句話介紹自己
</template>
</van-field>
<van-collapse accordion v-model="activeCollapse">
<van-collapse-item name="1">
<template #title>
<i class="fa-regular fa-gem text-darkBlue"></i> 我能分享的資源
</template>
<van-field
v-model="form.supply"
rows="3"
type="textarea"
maxlength="200"
placeholder="請填寫能分享的資源"
show-word-limit
/>
<van-field
v-model="form.supply_link"
name="pattern"
placeholder="分享網址"
:rules="[
{
validator: validatorUrl,
message: '網址格式不正確,Ex. http://',
},
]"
/>
</van-collapse-item>
<van-collapse-item name="2">
<template #title>
<i class="fa-regular fa-gem text-darkBlue"></i> 我需要的資源
</template>
<van-field
v-model="form.demand"
rows="3"
type="textarea"
maxlength="200"
placeholder="請填寫能分享的資源"
show-word-limit
/>
<van-field
v-model="form.demand_link"
name="pattern"
placeholder="需求連結"
/>
</van-collapse-item>
<van-collapse-item name="3">
<template #title>
<i class="fa-regular fa-gem text-darkBlue"></i> 菁英交流資訊
</template>
<van-field
v-model="form.exchange"
rows="3"
type="textarea"
maxlength="200"
placeholder="請填寫能分享的資源"
show-word-limit
/>
<van-field
v-model="form.exchange_link"
name="pattern"
placeholder="需求連結"
/>
</van-collapse-item>
</van-collapse>
<div class="p-5">
<van-button block class="btn-darkBlue" native-type="submit">
確認修改
</van-button>
</div>
</van-form>
</van-cell-group>
</div>
<van-popup class="cropPopup" v-model:show="crop.show" closeable>
<h5 class="text-center mt-3">檔案裁切上傳</h5>
<div class="cropper-section">
<div class="crop-area">
<cropper
class="cropper"
ref="myCrop"
:src="crop.img"
:stencil-props="{
aspectRatio: 1 / 1,
}"
:auto-zoom="true"
/>
</div>
<van-button
round
class="btn-tomatoRed rounded-pill w-50 mt-3"
size="small"
@click="onCrop"
>
裁切確認
</van-button>
</div>
</van-popup>
</template>
<style lang="less" scoped></style>

File diff suppressed because it is too large Load Diff

@ -1,8 +1,191 @@
<script setup>
import axios from "axios";
import { ref, inject } from "vue";
import store from "@/store";
import router from "@/router";
import { useRoute } from "vue-router";
import { showToast } from "vant";
import { showLoadingToast,showSuccessToast } from 'vant';
import { Cropper } from "vue-advanced-cropper";
import "vue-advanced-cropper/dist/style.css";
import { register, checkLineId } from "@/api";
const URL = window.URL || window.webkitURL;
const route = useRoute();
const form = ref({
verify: route.query.verify || null,
user_id: route.query.user_id || null,
aid: route.query.aid || undefined,
});
const title = ref("註冊成為會員");
const myCrop = ref(null);
const crop = ref({
show: false,
img: null,
});
if (route.query.verify || route.query.user_id) {
title.value = "會員開通";
}
const validatorUrl = (val) => {
if (val.length > 0) {
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val);
} else {
return true;
}
};
const leaveReg = () => {
window.location.replace("/error.html");
};
const onCrop = () => {
const { canvas } = myCrop.value.getResult();
if (canvas) {
const imgFile = new FormData();
canvas.toBlob(async (blob) => {
let ufile = new File([blob], "image.jpg");
imgFile.append("user_id", form.value.user_id);
imgFile.append("fileType", "IMAGE");
imgFile.append("file", ufile);
crop.value.show = false;
showLoadingToast({
duration: 0,
message: "圖片上傳中...",
forbidClick: true,
});
let res = await axios.post(
`${import.meta.env.VITE_APP_API_URL}/user/uploadAvatar`,
imgFile,
{}
);
if (res.data.code == 200) {
form.value.avatar = res.data.data;
showSuccessToast("上傳成功");
} else {
showToast.fail("上傳失敗");
}
}, "image/jpeg");
}
return;
};
const onClose = () => {
crop.value.show = false;
};
const afterRead = async (file, name) => {
crop.value.show = true;
const ofile = file.file;
crop.value.img = URL.createObjectURL(ofile);
return;
};
const onSubmit = async () => {
const liff = window.liff;
try {
if (!liff.isLoggedIn()) liff.login({ redirectUri: window.location.href });
} catch (err) {
console.log(`liff.state init error ${err}`);
showToast("登入失敗。請聯絡管理員");
router.push("/login");
}
const profile = await liff.getProfile();
let checkRes = await checkLineId(profile.userId);
if (checkRes.code !== 200) {
showToast("您已是我們的會員,請直接登入");
router.push("/login");
}
const id_token = liff.getIDToken();
showLoadingToast({
duration: 0,
message: "資料傳送中...",
forbidClick: true,
});
let regRes = await register({
line_id: profile.userId,
line_name: profile.displayName,
line_picture: profile.pictureUrl,
token: id_token,
...form.value,
});
console.log(regRes.code,"regRes.code")
if (regRes.code === 500) {
if (liff.isLoggedIn()) {
liff.logout();
}
showToast("line 登入已過期");
return;
} else if (regRes.code === 200) {
showToast("註冊成功");
sessionStorage.setItem("token", regRes.data.token);
sessionStorage.setItem("uid", regRes.data.uid);
return router.push("/");
} else {
showToast("註冊失敗");
return;
}
};
</script>
<template> <template>
<div class="reg-container"> <div class="reg-container page">
<van-nav-bar :title="title" /> <van-nav-bar class="bg-skyBlue py-2">
<template #title>
<h5 class="text-white mb-1"><strong>{{title}}</strong></h5>
</template>
</van-nav-bar>
<div class="content">
<van-form @submit="onSubmit"> <van-form @submit="onSubmit">
<van-cell-group inset> <van-cell-group inset>
<div class="text-center">
<van-uploader :after-read="afterRead" :max-count="1" name="averter" class="my-4">
<div class="upload-main">
<img
class="upload-img avatar"
:src="form.avatar"
alt=""
v-if="form.avatar"
/>
<img
class="upload-img avatar"
src="@/assets/images/upload.jpg"
alt=""
v-else
/>
<div class="ml-3">
<p class="text-skyBlue mb-2">上傳圖片預設為Line頭像</p>
<van-button class="btn-darkBlue" icon="plus" block type="primary" size="small">上傳檔案</van-button>
</div>
</div>
</van-uploader>
</div>
<van-field <van-field
v-model="form.real_name" v-model="form.real_name"
label="姓名" label="姓名"
@ -31,7 +214,10 @@
name="" name=""
required required
placeholder="Ex. 0900000001 不要有空格" placeholder="Ex. 0900000001 不要有空格"
:rules="[{ required: true, message: '手機號必填' },{ pattern: /\d{10}/ , message: '手機號格式錯誤' }]" :rules="[
{ required: true, message: '手機號必填' },
{ pattern: /\d{10}/, message: '手機號格式錯誤' },
]"
/> />
<van-field <van-field
v-model="form.tel" v-model="form.tel"
@ -45,7 +231,13 @@
name="" name=""
required required
placeholder="請輸入您的Email" placeholder="請輸入您的Email"
:rules="[{ required: true, message: 'Email必填' },{ pattern: /^([\w\.\-]){1,64}\@([\w\.\-]){1,64}/ , message: 'Email格式錯誤' }]" :rules="[
{ required: true, message: 'Email必填' },
{
pattern: /^([\w\.\-]){1,64}\@([\w\.\-]){1,64}/,
message: 'Email格式錯誤',
},
]"
/> />
<van-field <van-field
v-model="form.address" v-model="form.address"
@ -58,7 +250,9 @@
label="網址" label="網址"
name="" name=""
placeholder="請輸入您的網址" placeholder="請輸入您的網址"
:rules="[{ validator: validatorUrl, message: '網址格式不正確,Ex. http://' }]" :rules="[
{ validator: validatorUrl, message: '網址格式不正確,Ex. http://' },
]"
/> />
<van-field <van-field
v-model="form.line" v-model="form.line"
@ -84,247 +278,42 @@
name="" name=""
placeholder="請輸入您的Youtube連結" placeholder="請輸入您的Youtube連結"
/> />
<van-uploader
:after-read="afterRead"
:max-count="1"
name="averter"
>
<div class="upload-main">
<img class="upload-img" :src="form.avatar" alt="" v-if="form.avatar">
<img class="upload-img" src="@/assets/images/upload.jpg" alt="" v-else>
<p>上傳圖片,預設為Line頭像</p>
</div>
</van-uploader>
</van-cell-group> </van-cell-group>
<div style="margin: 16px;"> <div class="m-3 d-flex">
<van-button round block type="primary" native-type="submit"> <van-button round block class="btn-skyBlue rounded-pill mx-1" @click="leaveReg">
送出註冊 <h6>以後在說</h6>
</van-button> </van-button>
<br/> <van-button round block class="btn-darkBlue rounded-pill mx-1" native-type="submit">
<van-button round block type="default" @click="leaveReg"> <h6>送出註冊</h6>
以後在說
</van-button> </van-button>
</div> </div>
</van-form> </van-form>
<van-overlay :show="crop.show" @click="crop.show = false" /> </div>
<div class="cropper-section" v-if="crop.show">
<van-popup class="cropPopup" v-model:show="crop.show" round closeable>
<h5 class="text-center mt-3">檔案裁切上傳</h5>
<div class="cropper-section">
<div class="crop-area"> <div class="crop-area">
<cropper <cropper
class="cropper" class="cropper"
ref="myCrop" ref="myCrop"
:src="crop.img" :src="crop.img"
:stencil-props="{ :stencil-props="{
aspectRatio: 1/1 aspectRatio: 1 / 1,
}" }"
:auto-zoom="true" :auto-zoom="true"
/> />
</div> </div>
<div class="crop-btn"> <van-button round class="btn-tomatoRed rounded-pill w-50 mt-3" size="small" @click="onCrop">
<van-button type="primary" size="small" plain @click="onClose"></van-button> <h6>裁切確認</h6>
<van-button type="success" size="small" plain @click="onCrop"></van-button> </van-button>
</div>
</div> </div>
</van-popup>
</div> </div>
</template> </template>
<script setup> <style src="@/assets/css/main.css"></style>
import axios from 'axios'
import { ref } from 'vue'
import store from '@/store'
import router from '@/router'
import { useRoute } from 'vue-router'
import {Toast} from 'vant'
import { Cropper } from 'vue-advanced-cropper';
import 'vue-advanced-cropper/dist/style.css';
import { register , checkLineId } from '@/api'
const URL = window.URL || window.webkitURL;
const route = useRoute()
const form = ref({
verify: route.query.verify || null,
aid: route.query.aid || undefined
})
const title = ref('註冊成為會員')
const myCrop = ref(null)
const crop = ref({
show: false,
img: null,
})
if(route.query.verify){
title.value = '會員開通'
}
const validatorUrl = (val) => {
if(val.length>0){
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val)
}else{
return true
}
}
const leaveReg = ()=>{
window.location.replace('/error.html')
}
const onCrop = () => {
const { canvas } = myCrop.value.getResult();
if (canvas) {
const imgFile = new FormData();
canvas.toBlob(async (blob) => {
let ufile = new File([blob], "image.jpg");
imgFile.append("user_id", form.value.user_id)
imgFile.append("fileType", "IMAGE")
imgFile.append('file', ufile)
crop.value.show = false
Toast.loading({
duration: 0,
message: '圖片上傳中...',
forbidClick: true,
});
let res = await axios.post(
`${process.env.VUE_APP_API_URL}/user/uploadAvatar`,
imgFile,
{
}
)
if (res.data.code == 200) {
form.value.avatar = res.data.data
Toast.success('上傳成功');
}else{
Toast.fail('上傳失敗');
}
}, 'image/jpeg');
}
return
}
const onClose = () =>{
crop.value.show = false
}
const afterRead = async(file, name) => {
crop.value.show = true
const ofile = file.file
crop.value.img = URL.createObjectURL(ofile);
return
}
const onSubmit = async () => {
try{
if(!liff){
console.log('liff is undefined')
Toast('系統錯誤,請重新登入')
router.push('/login')
}
}catch(e){
console.log(e.message)
Toast('系統錯誤,請重新登入')
router.push('/login')
}
const profile = await liff.getProfile()
let checkRes = await checkLineId(profile.userId)
if(checkRes.code!==200){
Toast('您已是我們的會員,請直接登入')
router.push('/login')
}
const id_token = liff.getIDToken()
Toast.loading({
duration: 0,
message: '資料傳送中...',
forbidClick: true,
});
let regRes = await register({line_id: profile.userId, token: id_token , ...form.value})
if(regRes.code === 500){
if (liff.isLoggedIn()) {
liff.logout();
}
Toast('line 登入已過期')
// return router.push('/login')
}else if(regRes.code === 200){
Toast('註冊成功')
sessionStorage.setItem('token',regRes.data.token)
sessionStorage.setItem('uid',regRes.data.uid)
return router.push('/')
}else{
Toast('註冊失敗')
// return router.push('/login')
}
}
</script>
<style lang="less" scoped> <style lang="less" scoped>
.container{
padding-bottom: 30px;
}
.title{
font-size: 20px;
text-align: center;
}
.upload-img{
width: 80px;
}
.cropper {
height: 300px;
// width: 300px;
background: #DDD;
}
.cropper-section{
margin: 0 auto;
position: fixed;
text-align: center;
top: 50px;
// left: 0;
height: 350px;
width: 100%;
max-width: 500px;
background: #DDD;
z-index: 8888;
.crop-area{
margin: 5 auto;
width: 100%;
height: 330px;
}
.crop-btn{
background-color: #666;
text-align: center;
}
}
</style> </style>

@ -0,0 +1,344 @@
<template>
<div class="reg-container">
<van-nav-bar :title="title" />
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field
v-model="form.real_name"
label="姓名"
name="pattern"
required
placeholder="請輸入您的姓名"
:rules="[{ required: true, message: '姓名為必填' }]"
/>
<van-field
v-model="form.company"
label="公司名稱"
name=""
required
placeholder="請輸入您的公司名稱"
:rules="[{ required: true, message: '公司名稱必填' }]"
/>
<van-field
v-model="form.title"
label="職稱"
name=""
placeholder="請輸入您的職稱"
/>
<van-field
v-model="form.phone"
label="手機"
name=""
required
placeholder="Ex. 0900000001 不要有空格"
:rules="[
{ required: true, message: '手機號必填' },
{ pattern: /\d{10}/, message: '手機號格式錯誤' },
]"
/>
<van-field
v-model="form.tel"
label="市話"
name=""
placeholder="請輸入您的市話"
/>
<van-field
v-model="form.email"
label="Email"
name=""
required
placeholder="請輸入您的Email"
:rules="[
{ required: true, message: 'Email必填' },
{
pattern: /^([\w\.\-]){1,64}\@([\w\.\-]){1,64}/,
message: 'Email格式錯誤',
},
]"
/>
<van-field
v-model="form.address"
label="住址"
name=""
placeholder="請輸入您的地址"
/>
<van-field
v-model="form.url"
label="網址"
name=""
placeholder="請輸入您的網址"
:rules="[
{ validator: validatorUrl, message: '網址格式不正確,Ex. http://' },
]"
/>
<van-field
v-model="form.line"
label="Line"
name=""
placeholder="請輸入您的Line ID"
/>
<van-field
v-model="form.facebook"
label="Facebook"
name=""
placeholder="請輸入您的臉書連結"
/>
<van-field
v-model="form.ig"
label="IG"
name=""
placeholder="請輸入您的IG ID"
/>
<van-field
v-model="form.youtube"
label="YouTube"
name=""
placeholder="請輸入您的Youtube連結"
/>
<van-uploader :after-read="afterRead" :max-count="1" name="averter">
<div class="upload-main">
<img
class="upload-img"
:src="form.avatar"
alt=""
v-if="form.avatar"
/>
<img
class="upload-img"
src="@/assets/images/upload.jpg"
alt=""
v-else
/>
<p>上傳圖片,預設為Line頭像</p>
</div>
</van-uploader>
</van-cell-group>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
送出註冊
</van-button>
<br />
<van-button round block type="default" @click="leaveReg">
以後在說
</van-button>
</div>
</van-form>
<van-overlay :show="crop.show" @click="crop.show = false" />
<div class="cropper-section" v-if="crop.show">
<div class="crop-area">
<cropper
class="cropper"
ref="myCrop"
:src="crop.img"
:stencil-props="{
aspectRatio: 1 / 1,
}"
:auto-zoom="true"
/>
</div>
<div class="crop-btn">
<van-button type="primary" size="small" plain @click="onClose"
>取消</van-button
>
<van-button type="success" size="small" plain @click="onCrop"
>剪裁</van-button
>
</div>
</div>
</div>
</template>
<script setup>
import axios from "axios";
import { ref, inject } from "vue";
import store from "@/store";
import router from "@/router";
import { useRoute } from "vue-router";
import { showToast } from "vant";
import { showLoadingToast,showSuccessToast } from 'vant';
import { Cropper } from "vue-advanced-cropper";
import "vue-advanced-cropper/dist/style.css";
import { register, checkLineId } from "@/api";
const URL = window.URL || window.webkitURL;
const route = useRoute();
const form = ref({
verify: route.query.verify || null,
aid: route.query.aid || undefined,
});
const title = ref("註冊成為會員");
const myCrop = ref(null);
const crop = ref({
show: false,
img: null,
});
if (route.query.verify) {
title.value = "會員開通";
}
const validatorUrl = (val) => {
if (val.length > 0) {
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val);
} else {
return true;
}
};
const leaveReg = () => {
window.location.replace("/error.html");
};
const onCrop = () => {
const { canvas } = myCrop.value.getResult();
if (canvas) {
const imgFile = new FormData();
canvas.toBlob(async (blob) => {
let ufile = new File([blob], "image.jpg");
imgFile.append("user_id", form.value.user_id);
imgFile.append("fileType", "IMAGE");
imgFile.append("file", ufile);
crop.value.show = false;
showLoadingToast({
duration: 0,
message: "圖片上傳中...",
forbidClick: true,
});
let res = await axios.post(
`${import.meta.env.VITE_APP_API_URL}/user/uploadAvatar`,
imgFile,
{}
);
if (res.data.code == 200) {
form.value.avatar = res.data.data;
showSuccessToast("上傳成功");
} else {
showToast.fail("上傳失敗");
}
}, "image/jpeg");
}
return;
};
const onClose = () => {
crop.value.show = false;
};
const afterRead = async (file, name) => {
crop.value.show = true;
const ofile = file.file;
crop.value.img = URL.createObjectURL(ofile);
return;
};
const onSubmit = async () => {
const liff = window.liff;
try {
if (!liff.isLoggedIn()) liff.login({ redirectUri: window.location.href });
} catch (err) {
console.log(`liff.state init error ${err}`);
showToast("登入失敗。請聯絡管理員");
router.push("/login");
}
const profile = await liff.getProfile();
let checkRes = await checkLineId(profile.userId);
if (checkRes.code !== 200) {
showToast("您已是我們的會員,請直接登入");
router.push("/login");
}
const id_token = liff.getIDToken();
showLoadingToast({
duration: 0,
message: "資料傳送中...",
forbidClick: true,
});
let regRes = await register({
line_id: profile.userId,
line_name: profile.displayName,
line_picture: profile.pictureUrl,
token: id_token,
...form.value,
});
if (regRes.code === 500) {
if (liff.isLoggedIn()) {
liff.logout();
}
showToast("line 登入已過期");
return;
} else if (regRes.code === 200) {
showToast("註冊成功");
sessionStorage.setItem("token", regRes.data.token);
sessionStorage.setItem("uid", regRes.data.uid);
return router.push("/");
} else {
showToast("註冊失敗");
return;
}
};
</script>
<style lang="less" scoped>
.container {
padding-bottom: 30px;
}
.title {
font-size: 20px;
text-align: center;
}
.upload-img {
width: 80px;
}
.cropper {
height: 300px;
// width: 300px;
background: #ddd;
}
.cropper-section {
margin: 0 auto;
position: fixed;
text-align: center;
top: 50px;
// left: 0;
height: 350px;
width: 100%;
max-width: 500px;
background: #ddd;
z-index: 8888;
.crop-area {
margin: 5 auto;
width: 100%;
height: 330px;
}
.crop-btn {
background-color: #666;
text-align: center;
}
}
</style>

@ -1,73 +1,30 @@
<template>
<div id="home">
<van-nav-bar title="名片分享" />
<div class="tab-section" v-cloak>
<van-tabs :lazy-render="true" v-model:active="activeName" v-show="userInfo.nc_type > 1">
<van-tab title="我的名片" name="0">
</van-tab>
<van-tab :title="state.card_title" name="1" v-if="state.showCusCard">
</van-tab>
<van-tab :title="card.title" :name="card.id.toString()" v-for="card of state.vip_card" :key="card.id">
</van-tab>
</van-tabs>
<div class="flex-section">
<div class="table-responsive">
<div class="chatbox">
<div id="flex" ref="flexRef"></div>
</div>
</div>
</div>
<div class="preview-text">上面圖內分享無效請點下列分享</div>
</div>
<div class="btn-area" @click="sendEcard">
<van-button type="primary" block>分享好友</van-button>
</div>
<div class="btn-area" @click="showChangeTpl" v-show="activeName == '0'">
<van-button type="success" block>切換樣版</van-button>
</div>
<Footer />
<van-popup v-model:show="showDraw" position="right" :style="{ height: '100%', width: '150px' }">
<div>
<ul class="tpl-list">
<li class="tpl-item" @click="changeTpl(0)">
<img src="@/assets/images/tpl/tpl0.png">
</li>
<li class="tpl-item" @click="changeTpl(1)">
<img src="@/assets/images/tpl/tpl1.png">
</li>
<li class="tpl-item" @click="changeTpl(3)">
<img src="@/assets/images/tpl/tpl3.png">
</li>
</ul>
</div>
</van-popup>
</div>
</template>
<script setup> <script setup>
import liff from "@line/liff"; import liff from "@line/liff";
import { Toast } from 'vant'; import { showToast, showSuccessToast } from 'vant';
import { onMounted, reactive, ref, toRefs, computed, watch } from 'vue' import { onMounted, ref, computed, watch } from 'vue'
import { getCard, getCusCard, getVipCard, updateSendCount } from '@/api' import { getCard, getCusCard, getVipCard, updateSendCount, getFlexcard } from '@/api'
import { cardFactory } from '@/utils/card' import { cardFactory } from '@/utils/card'
import { genCard1 } from '@/utils/card2' import { genCard1 } from '@/utils/card2'
import { genVipCard } from '@/utils/vipcard' import { genVipCard } from '@/utils/vipcard'
import { useStore } from 'vuex' import { genAdCard } from '@/utils/adcard'
import { useUserStore } from '@/store/user';
import { useCardStore } from '@/store/card';
import Footer from '@/components/Footer' const userStore = useUserStore();
const cardStore = useCardStore();
const store = useStore() const imageUrl = ref(import.meta.env.VITE_APP_BASE_URL)
const state = ref({ const state = ref({
// active: 0, // active: 0,
showCusCard: false, showCusCard: false,
card_title: computed(() => store.state.user.userInfo.card_title), card_title: computed(() => cusCardInfo.value.card_title),
vip_card: [], vip_card: [],
flexContent: {}, flexContent: {},
}) })
@ -77,14 +34,24 @@ const activeName = ref('0');
let flexRef = ref(null) let flexRef = ref(null)
const userInfo = computed(() => { const userInfo = computed(() => {
return store.state.user.userInfo return userStore.userData;
}) });
const cusCardInfo = computed(() => {
return cardStore.cusCard;
});
// const vipCardInfo = computed(() => {
// return cardStore.vipCard;
// });
onMounted(async () => { onMounted(async () => {
// console.log('liff',liff) await liff.init({ liffId: import.meta.env.VITE_APP_LINE_LIFF_ID });
await liff.init({ liffId: process.env.VUE_APP_LINE_LIFF_ID });
await userStore.getUserData();
await cardStore.getCardData();
if (userInfo.value.nc_type > 2) { if (userInfo.value.level > 2) {
let vipCardRes = await getVipCard({ userid: sessionStorage.getItem('uid') }) let vipCardRes = await getVipCard({ userid: sessionStorage.getItem('uid') })
state.value.vip_card = vipCardRes.data state.value.vip_card = vipCardRes.data
} else { } else {
@ -92,37 +59,55 @@ onMounted(async () => {
} }
}) })
//tab
watch(() => activeName.value, function (newVal, oldVal) { watch(() => activeName.value, function (newVal, oldVal) {
if (newVal !== oldVal) { if (newVal !== oldVal) {
showFlex(newVal) showFlex(newVal)
} }
}, { immediate: true }) }, { immediate: true })
//
watch(() => userInfo.value.cus_card, function (newVal, oldVal) { watch(() => userInfo.value.cus_card, function (newVal, oldVal) {
if (userInfo.value.nc_type > 1 && newVal.length > 0) { // if (userInfo.value.level > 1 && newVal > 0) {
if (userInfo.value.level > 1) {
state.value.showCusCard = true state.value.showCusCard = true
} }
}, { immediate: true }) }, { immediate: true })
//NFC
watch(() => userInfo.value.nc_template, function (newVal, oldVal) { watch(() => userInfo.value.nc_template, function (newVal, oldVal) {
console.log('new', newVal)
showFlex('0') showFlex('0')
}) })
async function showFlex(id) { async function showFlex(id) {
switch (id) { switch (id) {
case '0': case '0':
let { data: res } = await getCard({ userid: sessionStorage.getItem('uid') }) let { data: res } = await getCard({ userid: sessionStorage.getItem('uid') })
let { card } = cardFactory({ tid: userInfo.value.nc_template, vcard: res }) let { card } = cardFactory({ tid: userInfo.value.nc_template, vcard: res })
// let { card } = genCard(res) if (userInfo.value.status !== 0 && !userInfo.value.is_send_ad) { // &
state.value.flexContent = JSON.parse(card) state.value.flexContent = JSON.parse(card)
} else {
let res2 = await getFlexcard();
if (res2.code === 200) {
if (res2.data.length !== 0) {
let data = res2.data;
data.ad_image = imageUrl.value + data.ad_image;
state.value.flexContent = genAdCard(JSON.parse(card), data);
}else{
state.value.flexContent = JSON.parse(card)
}
}
}
// console.log('card', JSON.stringify(state.value.flexContent) )
flexRef.value.innerHTML = '' flexRef.value.innerHTML = ''
flex2html("flex", state.value.flexContent) flex2html("flex", state.value.flexContent)
break break
case '1': case '1':
if (userInfo.value.nc_type > 1) { if (userInfo.value.level > 1) {
let card2Res = await getCusCard({ userid: sessionStorage.getItem('uid') }) let card2Res = await getCusCard({ userid: sessionStorage.getItem('uid') })
if (card2Res.code === 200) { if (card2Res.code === 200) {
if (card2Res.data.cus_card) { if (card2Res.data.cus_card) {
@ -136,7 +121,7 @@ async function showFlex(id) {
} }
break break
default: default:
if (userInfo.value.nc_type > 2) { if (userInfo.value.level > 2) {
// let vipCardRes = await getCusCard({userid: sessionStorage.getItem('uid')}) // let vipCardRes = await getCusCard({userid: sessionStorage.getItem('uid')})
let res = state.value.vip_card.find(item => { return item.id == id }) let res = state.value.vip_card.find(item => { return item.id == id })
if (res.type === 0) { if (res.type === 0) {
@ -169,9 +154,7 @@ const sendEcard = async () => {
let content = JSON.parse(JSON.stringify(state.value.flexContent)) let content = JSON.parse(JSON.stringify(state.value.flexContent))
// console.log('content', JSON.stringify(state.value.flexContent))
console.log(JSON.stringify(state.value.flexContent))
let res let res
if (activeName.value === '0') { if (activeName.value === '0') {
@ -186,7 +169,7 @@ const sendEcard = async () => {
if (res.status === 'success') { if (res.status === 'success') {
let result = await updateSendCount(userInfo.value.user_id) let result = await updateSendCount(userInfo.value.user_id)
Toast.success('傳送成功') showSuccessToast('傳送成功')
// .then(() => { // .then(() => {
// // on confirm // // on confirm
// }) // })
@ -194,7 +177,7 @@ const sendEcard = async () => {
// // on cancel // // on cancel
// }) // })
} else { } else {
Toast.fail('傳送失敗') showToast.fail('傳送失敗')
} }
} }
@ -217,14 +200,103 @@ function showChangeTpl() {
showDraw.value = true showDraw.value = true
} }
const changeTpl = (val) => { const changeTpl = async (val) => {
store.dispatch('user/setUserTpl', val) userStore.setUserTpl(val)
showDraw.value = false showDraw.value = false
} }
</script> </script>
<template>
<div class="member page bg-lightBlue">
<van-nav-bar class="bg-skyBlue py-1" left-arrow @click-left="$router.push('/')">
<template #title>
<h5 class="text-white mb-1"><strong>名片分享</strong></h5>
</template>
<template #left>
<h4><i class="fa-solid fa-angle-left text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
</van-nav-bar>
<div class="tab-section bg-lightPink" v-cloak>
<van-tabs :lazy-render="true" v-model:active="activeName" :ellipsis="false" v-show="userInfo.level > 1">
<van-tab name="0">
<template #title>
<div class="tab_item">
<i class="fa-regular fa-id-card fa-2x mb-1"></i>
<p class="mb-3">我的名片</p>
</div>
</template>
</van-tab>
<van-tab name="1" v-if="state.showCusCard">
<template #title>
<div class="tab_item">
<i class="fa-solid fa-clipboard fa-2x mb-1"></i>
<p class="mb-3">{{ state.card_title }}</p>
</div>
</template>
</van-tab>
<van-tab :name="card.id.toString()" v-for="card of state.vip_card" :key="card.id">
<template #title>
<div class="tab_item">
<i class="fa-regular fa-file-lines fa-2x mb-1"></i>
<p class="mb-3">{{ card.title }}</p>
</div>
</template>
</van-tab>
<!-- <van-tab :title="state.card_title" name="1" v-if="state.showCusCard"/>
<van-tab :title="card.title" :name="card.id.toString()" v-for="card of state.vip_card" :key="card.id"/> -->
</van-tabs>
<div class="flex-section">
<div class="table-responsive">
<div class="chatbox">
<!-- <div id="flex" ref="flexRef"></div> -->
<div id="flex" ref="flexRef"></div>
</div>
</div>
</div>
<h6 class="text-center text-white bg-darkBlue py-2">上面圖內分享無效請點下列分享</h6>
</div>
<van-sticky position="bottom">
<div class="bottomBtnCnt d-flex">
<van-button block class="btn-skyBlue m-2" @click="sendEcard">
<h6><i class="fa-solid fa-share-from-square"></i> 分享好友</h6>
</van-button>
<van-button block class="btn-tomatoRed m-2" @click="showChangeTpl" v-show="activeName == '0'">
<h6><i class="fa-solid fa-right-left"></i> 切換樣版</h6>
</van-button>
</div>
</van-sticky>
<van-popup v-model:show="showDraw" round position="bottom">
<div>
<ul class="tpl-list d-flex flex-wrap">
<li class="tpl-item" @click="changeTpl(0)">
<img src="@/assets/images/tpl/tpl0.png">
</li>
<li class="tpl-item" @click="changeTpl(1)">
<img src="@/assets/images/tpl/tpl1.png">
</li>
<li class="tpl-item" @click="changeTpl(2)">
<img src="@/assets/images/tpl/tpl2.png">
</li>
<li class="tpl-item" @click="changeTpl(3)">
<img src="@/assets/images/tpl/tpl3.png">
</li>
</ul>
</div>
</van-popup>
</div>
</template>
<style lang="less" scoped> <style lang="less" scoped>
.btn-area { .btn-area {
padding: 5px 15px padding: 5px 15px
@ -233,12 +305,12 @@ const changeTpl = (val) => {
.flex-section { .flex-section {
// color: white; // color: white;
// z-index: 99999; // z-index: 99999;
background-color: #666; background-color: #333;
} }
.chatbox { .chatbox {
background-color: #666; background-color: #222;
margin-top: 10px; margin-top: 10px;
padding-top: 10px; padding-top: 10px;
} }
@ -249,16 +321,10 @@ const changeTpl = (val) => {
overflow-x: auto; overflow-x: auto;
} }
.preview-text {
width: 100%;
background-color: #8e0325;
color: #FFF;
font-size: 18px;
text-align: center;
}
.tpl-list { .tpl-list {
.tpl-item { .tpl-item {
width: 150px;
padding: 10px; padding: 10px;
img { img {

@ -1,76 +1,68 @@
<template>
<div>
<van-nav-bar
title="立即購買"
right-text="關閉"
@click-right="$router.push('/')"
/>
<div class="main-section" v-html="shopContent">
</div>
</div>
<Footer/>
</template>
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { useStore } from 'vuex'
import { Toast } from 'vant' import { Toast } from 'vant'
import Footer from '@/components/Footer' // import Footer from '@/components/Footer.vue'
import { setUserLevel } from '@/api'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { getSiteConfig } from '@/api' import { getSiteConfig } from '@/api'
const store = useStore()
const router = useRouter() const router = useRouter()
const shopContent = ref('') const shopContent = ref('')
let res = await getSiteConfig() let res = await getSiteConfig()
console.log(res)
if (res.code === 200) { if (res.code === 200) {
store.commit('setSiteConfig',res.data) shopContent.value = res.data.shop_content
} else { } else {
Toast('系統錯誤') showToast('系統錯誤')
router.push('/home') router.push('/home')
} }
shopContent.value=store.state.config.shop_content
const setlevel = async (level)=>{
// let res = await setUserLevel(level)
// store.commit('user/setLevel',level)
// Toast('')
// router.push('/')
// window.location.href = 'http://www.tggo.com.tw/book.cgi?user=omo'
}
</script> </script>
<template>
<div class="shop page">
<van-nav-bar class="bg-skyBlue py-1" left-arrow @click-left="$router.push('/')">
<template #title>
<h5 class="text-white mb-1"><strong>立即購買</strong></h5>
</template>
<template #left>
<h4><i class="fa-solid fa-angle-left text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
</van-nav-bar>
<div class="main-section" v-html="shopContent">
</div>
</div>
<!-- <Footer/> -->
</template>
<style lang="less" scoped> <style lang="less" scoped>
.main-section { .main-section {
width: 100%; width: 100%;
} }
.recommend { .recommend {
width: 100%; width: 100%;
padding-top: 2%; padding-top: 2%;
} }
.recommend ul { .recommend ul {
width: 100%; width: 100%;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
} }
.recommend ul li { .recommend ul li {
width: 48%; width: 48%;
flex-direction: column; flex-direction: column;
margin: 1%; margin: 1%;
img { img {
width: 100%; width: 100%;
} }
} }</style>
</style>

@ -0,0 +1,39 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite';
import { VantResolver } from '@vant/auto-import-resolver';
import { resolve } from 'path';
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
return {
base: './',
server: {
host: '0.0.0.0',
port: 5173,
proxy: {
"/api": {
target: "https://utel.zltest.com.tw/appapi/v1",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
},
plugins: [
vue(),
Components({
resolvers: [
VantResolver(),
],
})
],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
// esbuild: {
// drop: ["console", "debugger"],
// },
}
})

@ -1,38 +0,0 @@
module.exports = {
devServer: {
disableHostCheck: true,
},
publicPath: ["production", "stage", "u168"].includes(process.env.VUE_ENV)
? "/home"
: "/home",
outputDir:
["production", "u168"].includes(process.env.VUE_ENV)
? "../ecard_api/public/home"
: "./dist",
pwa: {
name: "UTel電子名片",
short_name: "UTel",
background_color: "#3367D6",
display: "browser",
icons: [
{
src: "/img/icons/android-chrome-192x192.png",
type: "image/png",
sizes: "192x192",
},
{
src: "/img/icons/android-chrome-512x512.png",
type: "image/png",
sizes: "512x512",
},
],
themeColor: "#4DBA88",
// msTileColor: '#000000',
// appleMobileWebAppCapable: 'yes',
// appleMobileWebAppStatusBarStyle: 'black',
workboxPluginMode: "GenerateSW",
workboxOptions: {
skipWaiting: true,
},
},
};

11934
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save