Compare commits

..

No commits in common. 'dc0d0e7a261ac190e2f032f8bac4824e636eb3c3' and 'bfa85d546ce6effe22a301ea686ee209ac7e8c78' have entirely different histories.

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

@ -0,0 +1,15 @@
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
VITE_ENV = production VUE_ENV = production
VITE_APP_BASE_URL = https://pro.utel.vip VUE_APP_BASE_URL = https://utel.vip
VITE_APP_LINE_LIFF_ID = 1656969446-lO8Q477x VUE_APP_LINE_LIFF_ID = 1656969446-nQYlz77R
VITE_APP_SEND_URL = https://liff.line.me/1656969446-r07ayzzq VUE_APP_SEND_URL = https://liff.line.me/1656969446-mg36Maav
VITE_APP_API_URL = /appapi/v1 VUE_APP_API_URL = https://utel.vip/appapi/v1
VITE_APP_IMAGE_URL = /storage VUE_APP_IMAGE_URL = https://utel.vip/storage

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

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

25
.gitignore vendored

@ -1,26 +1,23 @@
# Logs .DS_Store
logs node_modules
*.log /dist
# 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
.DS_Store .vscode
*.suo *.suo
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
.env.development

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

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

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

Binary file not shown.

@ -1,13 +0,0 @@
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

@ -1,39 +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="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>

31847
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,45 +1,48 @@
{ {
"name": "utel_h5_vite", "name": "utel",
"version": "0.1.0",
"private": true, "private": true,
"version": "0.0.0",
"type": "module",
"scripts": { "scripts": {
"dev": "vite", "serve": "vue-cli-service serve",
"build": "vite build", "build": "vue-cli-service build",
"build:sta": "vite build --mode stage", "build:u168": "vue-cli-service build --mode u168",
"preview": "vite preview" "build:dev": "vue-cli-service build --mode development",
"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.22.4", "@line/liff": "^2.18.2",
"@soerenmartius/vue3-clipboard": "^0.1.2", "@soerenmartius/vue3-clipboard": "^0.1.2",
"axios": "^1.5.1", "axios": "^1.3.3",
"colorthief": "^2.4.0", "colorthief": "^2.3.2",
"core-js": "^3.6.5",
"ismobilejs": "^1.1.1", "ismobilejs": "^1.1.1",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.29.4", "moment": "^2.29.1",
"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.4.1", "qrcode.vue": "^3.3.3",
"register-service-worker": "^1.7.2", "register-service-worker": "^1.7.1",
"secure-ls": "^1.2.6", "secure-ls": "^1.2.6",
"vant": "^4.7.1", "vant": "^3.4.5",
"vue": "^3.3.4", "vue": "3.2.41",
"vue-advanced-cropper": "^2.8.8", "vue-advanced-cropper": "^2.8.1",
"vue-cropper": "^0.6.4", "vue-cropper": "^1.0.3",
"vue-router": "^4.2.5", "vue-router": "^4.0.0-0",
"vuex": "^4.1.0", "vuex": "^4.0.0-0",
"vuex-persistedstate": "^4.1.0" "vuex-persistedstate": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@vant/auto-import-resolver": "^1.0.1", "@vue/cli-plugin-babel": "~4.5.15",
"@vitejs/plugin-vue": "^4.2.3", "@vue/cli-plugin-pwa": "~4.5.15",
"less": "^4.2.0", "@vue/cli-plugin-router": "~4.5.15",
"terser": "^5.24.0", "@vue/cli-plugin-vuex": "~4.5.15",
"unplugin-vue-components": "^0.25.2", "@vue/cli-service": "~4.5.15",
"vite": "^4.4.5" "@vue/compiler-sfc": "3.2.41",
"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: 5px; border-radius: 17px;
} }
.LyKi .T1 { .LyKi .T1 {
border-radius: 10px; border-radius: 10px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

@ -0,0 +1,41 @@
<!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,31 +458,23 @@ 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";
if (color) {
style3 += `color:${color} !important;`;
}
// code block // code block
} }
} }
if (color) {
style3 += `background-color:${color} !important;`;
}
if ( if (
offsetTop && offsetTop &&
(offsetTop.indexOf("px") >= 0 || offsetTop.indexOf("%") >= 0) (offsetTop.indexOf("px") >= 0 || offsetTop.indexOf("%") >= 0)
@ -829,8 +821,6 @@ 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) {
@ -917,7 +907,7 @@ function text_object(json) {
style2 += `margin-top:${margin};`; style2 += `margin-top:${margin};`;
exmgn = ""; exmgn = "";
} else { } else {
exmgn = margin ? "ExMgnT" + upperalldigit(margin) : ""; exmgn = margin ? "ExMgnL" + upperalldigit(margin) : "";
} }
alg = alg =

@ -1,30 +1,25 @@
<template> <template>
<Suspense> <Suspense>
<template #default> <template #default>
<router-view /> <router-view/>
</template> </template>
<template #fallback> <template #fallback>
Loading Loading
</template> </template>
</Suspense> </Suspense>
</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: import.meta.env.VITE_APP_API_URL, baseURL: process.env.VUE_APP_API_URL,
timeout: 5000, timeout: 5000,
withCredentials: true withCredentials: true
}) })

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

@ -7,17 +7,10 @@ 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 () => export const getUserInfo = async () => ajax(`/user/getUserInfo`);
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");
@ -25,15 +18,6 @@ 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");
@ -60,44 +44,13 @@ export const updateSendCount = async (userid) =>
//授權使用者 //授權使用者
export const setAuthUser = async (params) => export const setAuthUser = async (params) =>
ajax(`/user/setAuthUser`, params, "POST"); ajax(`/user/setAuthUser`, params , "POST");
export const getAuthUsers = async () => export const getAuthUsers = async () =>
ajax(`/user/getAuthUsers`); ajax(`/user/getAuthUsers`);
export const delAuthUser = async (id) => export const delAuthUser = async (id) =>
ajax(`/user/delAuthUser`, { id }); ajax(`/user/delAuthUser`,{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");

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

@ -1,17 +0,0 @@
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.

Before

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 792 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 729 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 28 KiB

@ -1,883 +0,0 @@
{
"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": []
}
}

@ -1,113 +0,0 @@
//===
$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;
}
}

@ -1,138 +0,0 @@
@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;}

@ -1,53 +0,0 @@
$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;
}
}
}

@ -1,35 +0,0 @@
%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;
}
}

@ -1,178 +0,0 @@
[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%);
}

@ -1,17 +0,0 @@
.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;
}
}

@ -1,18 +0,0 @@
// @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

@ -1,6 +0,0 @@
@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 { showToast } from 'vant'; import { Toast } 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(import.meta.env.VITE_APP_IMAGE_URL) const imageUrl = ref(process.env.VUE_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/${import.meta.env.VITE_APP_LINE_LIFF_ID}/?aid=${store.state.user.userInfo.agent_prefix}`) toClipboard(`https://liff.line.me/${process.env.VUE_APP_LINE_LIFF_ID}/?aid=${store.state.user.userInfo.agent_prefix}`)
showToast('已放入剪貼簿') Toast('已放入剪貼簿')
} }
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,27 +1,9 @@
<template> <template>
<div class="preview page"> <van-nav-bar title="預覽:)" right-text="" @click-right="$router.back()" />
<van-nav-bar <div class="flex-section">
class="bg-skyBlue py-1" <div class="table-responsive">
@click-left="$router.push('/card')" <div class="chatbox">
> <div id="flex" ref="flexRef"></div>
<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="table-responsive">
<div class="chatbox">
<div id="flex" ref="flexRef"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -39,7 +21,7 @@ const flexRef = ref(null)
onActivated(() => { onActivated(() => {
flexRef.value.innerHTML = '' flexRef.value.innerHTML = ''
let flexContent = genCard1(JSON.parse(history.state.content)) let flexContent = genCard1(JSON.parse(route.params.content))
flex2html("flex", flexContent) flex2html("flex", flexContent)
}) })
@ -52,12 +34,12 @@ onDeactivated(() => {
.flex-section { .flex-section {
// color: white; // color: white;
// z-index: 99999; // z-index: 99999;
background-color: #333; background-color: #666;
} }
.chatbox { .chatbox {
background-color: #000; background-color: #666;
margin-top: 10px; margin-top: 10px;
padding-top: 10px; padding-top: 10px;
} }

@ -2,32 +2,16 @@ 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 liff from '@line/liff'; import { vant } from "@/plugins/vant";
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'
liff.init({ const vue = createApp(App);
liffId: import.meta.env.VITE_APP_LINE_LIFF_ID
}).then(() => {
window.liff = liff; vant(vue);
vue.use(VueClipboard);
const vue = createApp(App); vue.use(store).use(router).mount("#app");
pinia.use(piniaPluginPersistedstate);
// 將LIFF實例提供給應用
vue.use(VueClipboard);
vue.use(pinia);
// 初始化Store
vue.use(store).use(router).mount("#app");
}).catch((error) => {
console.error('初始化 LIFF 時出錯:', error);
});

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

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

@ -1,41 +0,0 @@
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, toggleSendWithAD } from "@/api"; import { getUserInfo, setUserTpl } from "@/api";
export default { export default {
namespaced: true, namespaced: true,
@ -18,9 +18,6 @@ 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) {
@ -35,15 +32,5 @@ 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;
}
}, },
}; };

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

@ -1,45 +0,0 @@
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
})

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

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

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

@ -1,7 +1,5 @@
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);

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

@ -1,11 +0,0 @@
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;

@ -1,496 +0,0 @@
<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,7 +1,50 @@
<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 { showToast,showSuccessToast } from 'vant'; import { Toast } from 'vant';
import { setAuthUser , delAuthUser , getAuthUsers } from '@/api' import { setAuthUser , delAuthUser , getAuthUsers } from '@/api'
@ -14,12 +57,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 showToast.fail('授權失敗,'+res.data); return Toast.fail('授權失敗,'+res.data);
} }
genAuthList(); genAuthList();
return showSuccessToast('授權成功'); return Toast.success('授權成功');
} }
// //
@ -41,12 +84,12 @@ const handleDelete = async (id)=>{
console.log(res) console.log(res)
if(res.code!==200){ if(res.code!==200){
return showToast.fail('刪除失敗'); return Toast.fail('刪除失敗');
} }
genAuthList(); genAuthList();
return showSuccessToast('刪除成功'); return Toast.success('刪除成功');
} }
@ -56,79 +99,15 @@ 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>
table#auth-list{ #auth-list{
width: 100%; width: 100%;
thead th{ td,th{
color: #fff; border: 1px solid #ddd;
background-color: #4a677d; padding: 3px;
} }
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.vue"; import Footer from "@/components/Footer";
import FlexView from "@/components/FlexView.vue"; import FlexView from "@/components/FlexView";
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 { showToast,showLoadingToast,showSuccessToast } from "vant"; import { Toast } 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;
showLoadingToast({ Toast.loading({
duration: 0, duration: 0,
message: "圖片上傳中...", message: "圖片上傳中...",
forbidClick: true, forbidClick: true,
}); });
let res = await axios.post( let res = await axios.post(
`${import.meta.env.VITE_APP_API_URL}/card/uploadfile`, `${process.env.VUE_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;
showSuccessToast("上傳成功"); Toast.success("上傳成功");
} else { } else {
showToast.fail("上傳失敗"); Toast.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: `${import.meta.env.VITE_APP_SEND_URL}?userid=${userid}&cardid=2`, link: `${process.env.VUE_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);
showLoadingToast({ Toast.loading({
duration: 0, duration: 0,
message: "圖片上傳中...", message: "圖片上傳中...",
forbidClick: true, forbidClick: true,
}); });
let res = await axios.post( let res = await axios.post(
`${import.meta.env.VITE_APP_API_URL}/card/uploadfile`, `${process.env.VUE_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;
showSuccessToast("上傳成功"); Toast.success("上傳成功");
} else { } else {
showToast.fail("上傳失敗"); Toast.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)) {
showToast("商務卡片欄位錯誤,紅色錯誤欄位請重新檢查!!"); Toast("商務卡片欄位錯誤,紅色錯誤欄位請重新檢查!!");
return; return;
} }
let user_id = userid; let user_id = userid;
showLoadingToast({ Toast.loading({
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));
showSuccessToast("建立成功"); Toast.success("建立成功");
} else { } else {
showToast.fail("建立失敗"); Toast.fail("建立失敗");
} }
router.push("/auth/getauth"); router.push("/auth/getauth");
}; };

@ -1,3 +1,22 @@
<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";
@ -19,54 +38,15 @@ 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>
table#auth-list{ #auth-list{
width: 100%; width: 100%;
thead th{ td,th{
color: #fff; border: 1px solid #ddd;
background-color: #4a677d; padding: 3px;
} }
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,38 +1,73 @@
<script setup>
import { useRouter} from 'vue-router'
import Footer from '@/components/Footer.vue'
const router = useRouter()
</script>
<template> <template>
<div class="level page"> <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>
<van-nav-bar class="bg-skyBlue py-1" left-arrow @click-left="$router.push('/')"> <script setup>
<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"> import { useRouter} from 'vue-router'
<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> import Footer from '@/components/Footer'
</div>
</van-cell-group> const router = useRouter()
</div>
</template>
<style src="@/assets/css/main.css"></style> </script>
<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>

@ -0,0 +1,52 @@
<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')" /> <van-nav-bar title="教學影片" right-text="" @click-right="$router.push('/card/edit')" />
<div class="yt-content"> <div class="yt-content">
<iframe width="375" height="215" src="https://www.youtube.com/embed/94q_MPZeU6s" title="Utel電子名片教學" <iframe width="375" height="215" src="https://www.youtube.com/embed/fjZsQ0Rh6yk" 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,634 +1,418 @@
<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 moment from "moment"; import liff from "@line/liff"
import QrcodeVue from "qrcode.vue"; import moment from 'moment'
import { toClipboard } from "@soerenmartius/vue3-clipboard"; import QrcodeVue from 'qrcode.vue'
import { toClipboard } from '@soerenmartius/vue3-clipboard'
import { ref, computed, onBeforeMount } from "vue"; import { ref, computed, onBeforeMount, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from 'vue-router';
import { useUserStore } from '@/store/user'; import { useStore } from 'vuex';
import { useCardStore } from '@/store/card';
import { showToast, showSuccessToast, showConfirmDialog } from "vant"; import { Toast } from 'vant'
import 'vant/es/toast/style'; import { Dialog } from 'vant';
import { login, bindCard, getMovie, getMarquee, bindUser } from "@/api"; import Footer from '@/components/Footer'
import noUserImg from '@/assets/images/upload.jpg' import { login, bindCard } from '@/api'
const router = useRouter();
const route = useRoute();
const userStore = useUserStore(); const router = useRouter()
const cardStore = useCardStore(); const route = useRoute()
const store = useStore()
const showShare = ref(false); const showShare = ref(false)
const showNfcQrcode = ref(false);
const showQrcode = ref(false);
const checked = ref(true); const showNfcQrcode = ref(false)
const imageUrl = ref(import.meta.env.VITE_APP_BASE_URL);
const is_due = ref(false); const imageUrl = ref(process.env.VUE_APP_IMAGE_URL)
const userLevel = {
0: '基礎款',
1: '標準款',
2: '自製款',
3: '客製款'
}
const is_due = ref(false)
onBeforeMount(async () => { onBeforeMount(async () => {
const liff = window.liff;
try { try {
if (!liff.isLoggedIn()) liff.login({ redirectUri: window.location.href }); await liff.init({ liffId: process.env.VUE_APP_LINE_LIFF_ID });
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}`);
showToast("登入失敗。請聯絡管理員"); Toast('登入失敗。請聯絡管理員')
router.push("/login"); router.push('/login')
} }
if (!sessionStorage.getItem("token")) { //
const profile = await liff.getProfile();
const id_token = liff.getIDToken(); 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 }); 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') {
showToast("您已經是本站會員"); Toast('您已經是本站會員')
} }
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) { //
if (route.query.act === "openright") { } else if (loginRes.code === 202) {
if (route.query.act === 'openright') {
if (route.query.verify) { if (route.query.verify) {
// //
showConfirmDialog({ Dialog.confirm({
title: "卡片綁定", title: '卡片綁定',
message: "確認是否綁定這張卡片", message: '確認是否綁定這張卡片'
confirmButtonText: "確認", }).then(async () => {
cancelButtonText: "取消", //
let bindRes = await bindCard({ uid: loginRes.data.uid, verify: route.query.verify })
if (bindRes.code === 200) {
Toast.success('綁定成功')
} else {
Toast.fail('綁定失敗')
}
}).catch(() => {
}) })
.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('token', loginRes.data.token)
sessionStorage.setItem("uid", loginRes.data.uid); sessionStorage.setItem('uid', loginRes.data.uid)
} else if (loginRes.code === 201) { //
if (route.query.act === "openright") { // } else if (loginRes.code === 201) {
if (route.query.verify) { // if (route.query.act === 'openright') {
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 () => {
// return
let bindRes = await bindUser({
line_id: profile.userId,
user_id: route.query.user_id,
});
if (bindRes.code === 200) {
showSuccessToast("綁定成功");
} else {
showFailToast("綁定失敗");
return;
}
})
.catch(() => { });
} }
} 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 {
showToast("請先註冊成為本站會員"); Toast('請先註冊成為本站會員')
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();
});
/**
* 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(); } else {
if (res.code === 200) { Toast('登入失敗。請聯絡管理員')
// res.dataObject router.push('/login')
if (Object.keys(res.data).length !== 0) {
adData.value = res.data;
popShow.value = true;
}
} }
} }
};
const popShow = ref(false); store.dispatch('user/getUserInfo')
const modalClose = ref(false);
const closeShow = () => { //
modalClose.value = true; nextTick(() => {
};
// 使computed, userInfo.value.is_send_ad // if(userInfo.value.level===0 && userInfo.value.nc_type===0){
// const adSwitchStatus = ref(Boolean(userInfo.value.is_send_ad)); // Toast('')
const adSwitchStatus = computed(() => { // return router.push('/shop/inputsn')
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 userStore.userData; return store.state.user.userInfo
}); })
const nfcurl = computed(() => { const nfcurl = computed(() => {
return encodeURI(userStore.userData.ufcurl); return encodeURI(store.state.user.userInfo.ufcurl)
}); })
const overdue = computed(() => { const overdue = computed(() => {
if (userStore.userData.overdue_time > 0) { if (store.state.user.userInfo.overdue_time > 0) {
return moment return moment.unix(store.state.user.userInfo.overdue_time).format('YYYY-MM-DD')
.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) {
if (userInfo.value.level < 2) { router.push('/card/notice')
router.push("/card/notice");
} else { } else {
router.push("/card"); router.push('/card/edit')
} }
}; }
const onSelect = (option) => { const onSelect = (option) => {
showToast(option.name); Toast(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)
showToast("已放入剪貼簿"); Toast('已放入剪貼簿')
}; }
const doCopyUid = () => { const doCopyUid = () => {
toClipboard(userInfo.value.user_id); toClipboard(userInfo.value.user_id)
showToast("已放入剪貼簿"); Toast('已放入剪貼簿')
}; }
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 = () => {
if (userInfo.value.uniqid) { console.log(userInfo.value)
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");
return; window.open(url, '_blank');
} }
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>
<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="" </script>
: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)' }"> <style src="@/assets/css/style.css"></style>
<div class="wrapper" @click.stop> <style lang="less" scoped>
<div class="clip"> [ v-cloak] {
<van-icon :style="{ display: 'none', marginRight: '5px' }" @click="popShow = false" display: none;
: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> .recommend {
width: 100%;
padding-top: 2%;
}
<style lang="less" scoped> .recommend ul {
.home { width: 100%;
.wrapper { display: flex;
display: flex; flex-wrap: wrap;
justify-content: center; justify-content: space-between;
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 { .recommend ul li {
position: relative; box-sizing: content-box;
display: flex;
align-items: center; width: 44%;
width: 100%; height: 50px;
flex: 1 0 0; padding: 2%;
} display: flex;
flex-direction: column;
margin: 1%;
-webkit-box-shadow: 0 0 2px #fdaf00;
-moz-box-shadow: 0 0 2px #fdaf00;
box-shadow: 0 0 2px #fdaf00;
}
.bottom { .recommend ul li p {
position: relative; margin-top: 2%;
width: 100%; font-size: 15px;
flex: 0 0 auto; color: #333;
padding: 15px; }
.title { .recommend ul li span {
color: #ffffff; font-size: 14px !important;
font-weight: bold; color: #999 !important;
margin-bottom: 15px; padding-top: 0.15rem !important;
} }
.desc { .recommend ul li:nth-child(1) {
color: #ffffff; background: url(~@/assets/images/icon-001.png) right 0.3rem center no-repeat #fff !important;
margin-bottom: 30px; background-size: 30px !important;
} }
}
}
.my-account { .recommend ul li:nth-child(2) {
position: relative; background: url(~@/assets/images/icon-002.png) right 0.3rem center no-repeat #fff !important;
width: 100%; background-size: 30px !important;
padding: 20px 25px; }
.avatar {
display: flex;
justify-content: space-between;
align-items: center;
.left {
display: flex;
align-items: center;
flex: 1 0 0;
.imgCnt {
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;
}
}
.info { .recommend ul li:nth-child(3) {
.name { background: url(~@/assets/images/icon-003.png) right 0.3rem center no-repeat #fff !important;
font-weight: bold; background-size: 30px !important;
color: #303a47; }
}
.conpany { .recommend ul li:nth-child(4) {
margin-top: 5px; background: url(~@/assets/images/icon-004.png) right 0.3rem center no-repeat #fff !important;
} background-size: 30px !important;
} }
}
.right { .qrcode {
flex: 0 0 auto; text-align: center;
} }
}
.recommend { .input-sn {
display: flex; color: red !important;
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;
}
.text { .cp-btn {
font-size: 16px; border: #999 1px solid;
font-weight: bold; padding: 2px;
color: #345068; color: rgb(254, 104, 103);
}
}
}
}
} }
</style> </style>

@ -1,104 +0,0 @@
<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 { showToast } from 'vant' import { Toast } 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)
showToast('登入成功') Toast('登入成功')
// return router.push('/') // return router.push('/')
}else if(loginRes.code===201){ }else if(loginRes.code===201){
showToast('請先註冊成為本站會員') Toast('請先註冊成為本站會員')
return router.push('/register') return router.push('/register')
} }
showToast('登入失敗。請聯絡管理員') Toast('登入失敗。請聯絡管理員')
// console.log(loginRes) // console.log(loginRes)
// let checkLine = await checkLineId(profile.userId) // let checkLine = await checkLineId(profile.userId)

@ -1,169 +0,0 @@
<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>

@ -1,196 +0,0 @@
<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>

@ -1,70 +0,0 @@
<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>

@ -1,435 +0,0 @@
<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,319 +1,330 @@
<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> <script setup>
import axios from "axios"; import axios from 'axios'
import { ref, inject } from "vue";
import store from "@/store"; import { ref } from 'vue'
import router from "@/router";
import { useRoute } from "vue-router";
import { showToast } from "vant"; import store from '@/store'
import { showLoadingToast,showSuccessToast } from 'vant'; import router from '@/router'
import { useRoute } from 'vue-router'
import { Cropper } from "vue-advanced-cropper"; import {Toast} from 'vant'
import "vue-advanced-cropper/dist/style.css";
import { register, checkLineId } from "@/api"; 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 URL = window.URL || window.webkitURL;
const route = useRoute(); const route = useRoute()
const form = ref({ const form = ref({
verify: route.query.verify || null, verify: route.query.verify || null,
user_id: route.query.user_id || null, aid: route.query.aid || undefined
aid: route.query.aid || undefined, })
});
const title = ref("註冊成為會員"); const title = ref('註冊成為會員')
const myCrop = ref(null); const myCrop = ref(null)
const crop = ref({ const crop = ref({
show: false, show: false,
img: null, img: null,
}); })
if (route.query.verify || route.query.user_id) { if(route.query.verify){
title.value = "會員開通"; title.value = '會員開通'
} }
const validatorUrl = (val) => { const validatorUrl = (val) => {
if (val.length > 0) { if(val.length>0){
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val); return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val)
} else { }else{
return true; 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 = () => { const leaveReg = ()=>{
crop.value.show = false; 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('上傳失敗');
}
const afterRead = async (file, name) => { }, 'image/jpeg');
crop.value.show = true; }
const ofile = file.file; 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); crop.value.img = URL.createObjectURL(ofile);
return; return
}; }
const onSubmit = async () => { const onSubmit = async () => {
const liff = window.liff; try{
try { if(!liff){
if (!liff.isLoggedIn()) liff.login({ redirectUri: window.location.href }); console.log('liff is undefined')
} catch (err) { Toast('系統錯誤,請重新登入')
console.log(`liff.state init error ${err}`); router.push('/login')
showToast("登入失敗。請聯絡管理員"); }
router.push("/login"); }catch(e){
} console.log(e.message)
Toast('系統錯誤,請重新登入')
router.push('/login')
const profile = await liff.getProfile(); }
let checkRes = await checkLineId(profile.userId); const profile = await liff.getProfile()
if (checkRes.code !== 200) { let checkRes = await checkLineId(profile.userId)
showToast("您已是我們的會員,請直接登入");
router.push("/login");
}
const id_token = liff.getIDToken(); if(checkRes.code!==200){
Toast('您已是我們的會員,請直接登入')
showLoadingToast({ router.push('/login')
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> const id_token = liff.getIDToken()
<div class="reg-container page">
<van-nav-bar class="bg-skyBlue py-2"> Toast.loading({
<template #title> duration: 0,
<h5 class="text-white mb-1"><strong>{{title}}</strong></h5> message: '資料傳送中...',
</template> forbidClick: true,
</van-nav-bar> });
<div class="content"> let regRes = await register({line_id: profile.userId, token: id_token , ...form.value})
<van-form @submit="onSubmit">
<van-cell-group inset> if(regRes.code === 500){
<div class="text-center"> if (liff.isLoggedIn()) {
<van-uploader :after-read="afterRead" :max-count="1" name="averter" class="my-4"> liff.logout();
<div class="upload-main"> }
<img Toast('line 登入已過期')
class="upload-img avatar" // return router.push('/login')
:src="form.avatar" }else if(regRes.code === 200){
alt="" Toast('註冊成功')
v-if="form.avatar" sessionStorage.setItem('token',regRes.data.token)
/> sessionStorage.setItem('uid',regRes.data.uid)
<img return router.push('/')
class="upload-img avatar" }else{
src="@/assets/images/upload.jpg" Toast('註冊失敗')
alt="" // return router.push('/login')
v-else }
/> }
<div class="ml-3">
<p class="text-skyBlue mb-2">上傳圖片預設為Line頭像</p> </script>
<van-button class="btn-darkBlue" icon="plus" block type="primary" size="small">上傳檔案</van-button>
</div>
</div>
</van-uploader>
</div>
<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-cell-group>
<div class="m-3 d-flex">
<van-button round block class="btn-skyBlue rounded-pill mx-1" @click="leaveReg">
<h6>以後在說</h6>
</van-button>
<van-button round block class="btn-darkBlue rounded-pill mx-1" native-type="submit">
<h6>送出註冊</h6>
</van-button>
</div>
</van-form>
</div>
<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">
<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">
<h6>裁切確認</h6>
</van-button>
</div>
</van-popup>
</div>
</template>
<style src="@/assets/css/main.css"></style>
<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>

@ -1,344 +0,0 @@
<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,30 +1,73 @@
<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 { showToast, showSuccessToast } from 'vant'; import { Toast } from 'vant';
import { onMounted, ref, computed, watch } from 'vue' import { onMounted, reactive, ref, toRefs, computed, watch } from 'vue'
import { getCard, getCusCard, getVipCard, updateSendCount, getFlexcard } from '@/api' import { getCard, getCusCard, getVipCard, updateSendCount } 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 { genAdCard } from '@/utils/adcard' import { useStore } from 'vuex'
import { useUserStore } from '@/store/user';
import { useCardStore } from '@/store/card';
const userStore = useUserStore(); import Footer from '@/components/Footer'
const cardStore = useCardStore();
const imageUrl = ref(import.meta.env.VITE_APP_BASE_URL) const store = useStore()
const state = ref({ const state = ref({
// active: 0, // active: 0,
showCusCard: false, showCusCard: false,
card_title: computed(() => cusCardInfo.value.card_title), card_title: computed(() => store.state.user.userInfo.card_title),
vip_card: [], vip_card: [],
flexContent: {}, flexContent: {},
}) })
@ -34,24 +77,14 @@ const activeName = ref('0');
let flexRef = ref(null) let flexRef = ref(null)
const userInfo = computed(() => { const userInfo = computed(() => {
return userStore.userData; return store.state.user.userInfo
}); })
const cusCardInfo = computed(() => {
return cardStore.cusCard;
});
// const vipCardInfo = computed(() => {
// return cardStore.vipCard;
// });
onMounted(async () => { onMounted(async () => {
await liff.init({ liffId: import.meta.env.VITE_APP_LINE_LIFF_ID }); // console.log('liff',liff)
await liff.init({ liffId: process.env.VUE_APP_LINE_LIFF_ID });
await userStore.getUserData();
await cardStore.getCardData();
if (userInfo.value.level > 2) { if (userInfo.value.nc_type > 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 {
@ -59,55 +92,37 @@ 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.level > 1 && newVal > 0) { if (userInfo.value.nc_type > 1 && newVal.length > 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 })
if (userInfo.value.status !== 0 && !userInfo.value.is_send_ad) { // & // let { card } = genCard(res)
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.level > 1) { if (userInfo.value.nc_type > 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) {
@ -121,7 +136,7 @@ async function showFlex(id) {
} }
break break
default: default:
if (userInfo.value.level > 2) { if (userInfo.value.nc_type > 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) {
@ -154,7 +169,9 @@ 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') {
@ -169,7 +186,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)
showSuccessToast('傳送成功') Toast.success('傳送成功')
// .then(() => { // .then(() => {
// // on confirm // // on confirm
// }) // })
@ -177,7 +194,7 @@ const sendEcard = async () => {
// // on cancel // // on cancel
// }) // })
} else { } else {
showToast.fail('傳送失敗') Toast.fail('傳送失敗')
} }
} }
@ -200,103 +217,14 @@ function showChangeTpl() {
showDraw.value = true showDraw.value = true
} }
const changeTpl = async (val) => { const changeTpl = (val) => {
userStore.setUserTpl(val) store.dispatch('user/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
@ -305,12 +233,12 @@ const changeTpl = async (val) => {
.flex-section { .flex-section {
// color: white; // color: white;
// z-index: 99999; // z-index: 99999;
background-color: #333; background-color: #666;
} }
.chatbox { .chatbox {
background-color: #222; background-color: #666;
margin-top: 10px; margin-top: 10px;
padding-top: 10px; padding-top: 10px;
} }
@ -321,10 +249,16 @@ const changeTpl = async (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,68 +1,76 @@
<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 { Toast } from 'vant' import { useStore } from 'vuex'
// import Footer from '@/components/Footer.vue' import {Toast} from 'vant'
import { useRouter } from 'vue-router' import Footer from '@/components/Footer'
import { setUserLevel } from '@/api'
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) {
shopContent.value = res.data.shop_content
} else {
showToast('系統錯誤')
router.push('/home')
}
</script> if(res.code===200){
store.commit('setSiteConfig',res.data)
}else{
Toast('系統錯誤')
router.push('/home')
}
<template> shopContent.value=store.state.config.shop_content
<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"> const setlevel = async (level)=>{
</div> // let res = await setUserLevel(level)
</div> // store.commit('user/setLevel',level)
<!-- <Footer/> --> // Toast('')
</template> // router.push('/')
// window.location.href = 'http://www.tggo.com.tw/book.cgi?user=omo'
}
</script>
<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>

@ -1,39 +0,0 @@
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"],
// },
}
})

@ -0,0 +1,38 @@
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