Compare commits

..

110 Commits
dev ... main

Author SHA1 Message Date
Wayne cc59af9aad 0001257
2 years ago
Wayne e4439433d3 Merge branch 'sta'
2 years ago
Wayne fe1ad1f98a 0001245
2 years ago
Wayne 39b5bd0ab5 Merge branch 'sta'
2 years ago
Wayne eafd24ff65 0001247
2 years ago
Wayne be6f1aee23 0001246
2 years ago
Wayne 4ba596edca Merge branch 'sta'
2 years ago
Wayne 605cdb30d7 0001242
2 years ago
Wayne 4bb4229dd8 Merge branch 'sta'
2 years ago
Wayne 9b080e37f9 fix20240809
2 years ago
Wayne 7487871484 0001224
2 years ago
Wayne 3834c55abe 0001223
2 years ago
Wayne f41a23e851 Merge branch 'sta'
2 years ago
Wayne 30acb05ca0 0001222
2 years ago
Wayne cd1c12dd3f 0001222
2 years ago
Wayne cfe5eba817 bug fixed
2 years ago
Wayne eed9a1eaca 0001153
2 years ago
Wayne 13d47f941e Merge branch 'sta'
2 years ago
Wayne 150ab7d9d4 0001061
2 years ago
Wayne 9fbb42c5dd 先隱藏連結淘金購
2 years ago
Wayne 51aa9452d4 先隱藏代客編輯
2 years ago
Wayne 23a6348e4f 0001050
2 years ago
Wayne dc0d0e7a26 0000998
2 years ago
bruce68410 f5fa9cccfa 0000946
2 years ago
Wayne 3a7a91b496 0000969
2 years ago
bruce68410 224ec188ac 授權頁面文字修正、版型示意圖片修改
2 years ago
Wayne 0cb90ffe7e 0000954
2 years ago
Wayne cddada9408 0000954
2 years ago
bruce68410 fcbc94fd2a 0000942
2 years ago
bruce68410 3a6d13162b 0000939
2 years ago
Wayne 2c6c89a3ed 0000933
2 years ago
bruce68410 62b7fb2ef2 預覽頁面高度調整
2 years ago
DESKTOP-8UQ1PPR\09158 7b9d560788 0000930
2 years ago
bruce68410 879fbdc151 0000925
2 years ago
Wayne b194ffd690 修改地區及工作性質問題
2 years ago
bruce68410 78d1e9845b 補上圖片網址輸入欄位
2 years ago
bruce68410 fb7be73a6e 處理錯誤訊息 (改回原本
2 years ago
bruce68410 06c4a5bb4a 將預設的ellipsis關閉
2 years ago
bruce68410 bf4cae338e 處理錯誤訊息
2 years ago
Wayne 8d42353a6c 0000876
2 years ago
Wayne 5c0a63d855 0000880
2 years ago
bruce68410 d56e4f4008 發到LINE的名片,加上版型底圖連結、自我介紹及資源改為5行
2 years ago
DESKTOP-8UQ1PPR\09158 69cee05bec 卡片發布調整
2 years ago
DESKTOP-8UQ1PPR\09158 443acf6cc3 修改人脈資源文字
2 years ago
DESKTOP-8UQ1PPR\09158 a843ef4e57 修改四個版型的預覽文字 (補字)
2 years ago
bruce68410 c6b742e903 預覽圖修改、首頁選單icon修改
2 years ago
Wayne 5843aa3bc1 Merge branch 'dev' into sta
2 years ago
Wayne b62a6a694e 使用proxy,處理cors問題
2 years ago
DESKTOP-8UQ1PPR\09158 e861b4f988 人脈資源文字調整
2 years ago
Wayne 89375c64bd remove console.log
2 years ago
Wayne ce432ada07 0000866
2 years ago
Wayne 3e54bc1e36 會員資料欄位檢驗
2 years ago
Wayne 7d53365d12 0000852
2 years ago
Wayne d19f2426a6 Merge branch 'dev' into sta
2 years ago
Wayne 7ff6f225ae 0000838
2 years ago
Wayne c9661a0dc0 會員開通
2 years ago
Wayne 163ef76626 nfc連結及hide版型
2 years ago
Wayne 2951358fcd 0000838
2 years ago
Wayne 3cf93201e3 會員開通
2 years ago
Wayne 355e65749a nfc連結及hide版型
2 years ago
Wayne 822ba3c881 nfc連結
2 years ago
Wayne 30a5f6c53b 版型修改
2 years ago
Wayne 6c6ff6fcd4 0000835
2 years ago
Wayne 3e2df10116 0000833
2 years ago
Wayne f7515aab19 0000826
2 years ago
Wayne 486aa23da7 0000827
2 years ago
Wayne aa59a1068f 0000815,未登入時需先登入
2 years ago
Wayne db77b14659 0000815,未登入時需先登入
2 years ago
Wayne 370963f653 0000815
2 years ago
Wayne 1fc1dfd7a7 0000815
2 years ago
Wayne 54bbae189b 0000801
2 years ago
Wayne 53daffd285 0000812
2 years ago
Wayne 088dca0355 0000810
2 years ago
Wayne 46a1611f76 0000811
2 years ago
Wayne e9dfe78ea9 0000813
2 years ago
Wayne e4e8d5d13a 0000813
2 years ago
Wayne daa3c8145a 0000803
2 years ago
Wayne 46a3998f09 0000802
2 years ago
Wayne d0930be7d1 0000804
2 years ago
Wayne 24383d4ead 經銷商提供會員註冊
2 years ago
Wayne 8da54e528e 註冊時帶上經銷代碼
2 years ago
DESKTOP-8UQ1PPR\09158 a14c38747f 調整代客&授權編輯頁面css
2 years ago
DESKTOP-8UQ1PPR\09158 105440ea8d 標頭層級調整
2 years ago
Wayne d3ad65cea7 修改會員資料bug
2 years ago
Wayne f1d3ad7dc9 影片廣告bug
2 years ago
Wayne 00a3369baf 修正通訊錄類別更改後,id值沒改變問題
2 years ago
Wayne 50a156e16a 通訊錄 - 設定類別後更新
2 years ago
Wayne a56c5470e2 通訊錄 - 設定類別後更新
2 years ago
Wayne 8033a7f261 通訊錄 - 設定用戶類別及部份修正
2 years ago
bruce68410 b406125e5d 物件問題解決寫回
2 years ago
bruce68410 a7de319c42 Merge branch 'feature_231129' into dev
2 years ago
bruce68410 1acade3753 頁面功能列及確認按鈕固定置頂置底、通訊錄製作(類別設定、篩選)
2 years ago
bruce68410 35f8691a59 主頁調整、通訊錄製作
2 years ago
Wayne 15af258de7 卡片第三種版型json格式修改
2 years ago
bruce68410 c583ac9982 修正名片分享跑版問題
2 years ago
bruce68410 5f134c034b css修改
2 years ago
bruce68410 6c0d12d328 Merge remote-tracking branch 'origin/feature_231122' into feature_231122
2 years ago
bruce68410 6c7f503e8c hook使用方式修正、api串接更改
2 years ago
Wayne 8a4ac9e844 將watch移出onMounted
2 years ago
bruce68410 e7a0d071ce 修改send頁面 > 以pinia方式處理、新增名片廣告及判斷
2 years ago
DESKTOP-8UQ1PPR\09158 d07a8c2f8d 頁面修改、api串接
2 years ago
DESKTOP-8UQ1PPR\09158 c8c4d6e1c5 Merge branch 'feature_231120' into dev
2 years ago
bruce68410 2a958df547 附加廣告功能測試
2 years ago
Wayne 58b5b000a5 修改getUserData API - 2
2 years ago
Wayne a7bd5998f3 修改getUserData API
2 years ago
DESKTOP-8UQ1PPR\09158 d408a5dc4e 首頁選單按鈕位置調整、編輯頁顏色及文字調整
2 years ago
Wayne 908a601f7e 將商務卡片改為/card
3 years ago
Wayne 345da1f3f3 修改發送名片問題
3 years ago
Wayne 71ead16745 將發送名片的vuex換到pinia
3 years ago
Wayne 41bd11ab97 將發送名片的vuex換到pinia
3 years ago

@ -2,12 +2,12 @@ NODE_ENV = production
VITE_ENV = production
VITE_APP_BASE_URL = https://utel.vip
VITE_APP_BASE_URL = https://pro.utel.vip
VITE_APP_LINE_LIFF_ID = 1656969446-nQYlz77R
VITE_APP_LINE_LIFF_ID = 1656969446-lO8Q477x
VITE_APP_SEND_URL = https://liff.line.me/1656969446-mg36Maav
VITE_APP_SEND_URL = https://liff.line.me/1656969446-r07ayzzq
VITE_APP_API_URL = https://utel.vip/appapi/v1
VITE_APP_API_URL = /appapi/v1
VITE_APP_IMAGE_URL = https://utel.vip/storage
VITE_APP_IMAGE_URL = /storage

@ -1,6 +1,6 @@
NODE_ENV = development
VITE_ENV = stage
VITE_ENV = development
VITE_APP_BASE_URL = https://utel.zltest.com.tw

@ -6,8 +6,11 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"build:hot": "vite build",
"build:sta": "vite build --mode stage",
"preview": "vite preview"
"preview": "vite preview",
"postbuild:sta" : "scp -r ./dist/* root@207.148.89.145:/www/wwwroot/utel.zltest.com.tw/public/home",
"postbuild:hot" : "scp -r ./dist/* root@167.179.106.36:/www/wwwroot/pro.utel.vip/app/public/home"
},
"dependencies": {
"@line/liff": "^2.22.4",

@ -152,7 +152,7 @@ strong {
margin: 0 7px;
}
.LyMe .T1 {
border-radius: 17px;
border-radius: 5px;
}
.LyKi .T1 {
border-radius: 10px;

@ -829,6 +829,8 @@ function bubble_struc(json) {
direction = !direction || direction == "" ? "ltr" : direction;
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>`;
}
function hero_struc(json) {

@ -1,6 +1,10 @@
import ajax from "./ajax";
//通訊錄
export const getCardData = async () =>
ajax(`/Card/getCardData`);
export const updateRemark = async (params) =>
ajax(`/card/updateRemark`, params, "POST");
export const updateIsSend = async (params) =>
ajax(`/card/updateIsSend`, params, "POST");

@ -0,0 +1,13 @@
import ajax from "./ajax";
export const getFaviLogs = async (id) =>
ajax(`/faviLog/getFaviLogs`,{id},"GET");
export const addFaviLog = async (params) =>
ajax(`/faviLog/addFaviLog`,params,"POST");
export const deleteFaviLog = async (id) =>
ajax(`/faviLog/deleteFaviLog`,{id},"GET");
export const updateFaviLog = async (params) =>
ajax(`/faviLog/updateFaviLog`,params,"POST");

@ -7,6 +7,9 @@ export const login = async (params) => ajax(`/auth/login`, params, "POST");
export const bindCard = async (params) =>
ajax(`/auth/bindCard`, params, "POST");
export const bindUser = async (params) =>
ajax(`/auth/bindUser`, params, "POST");
export const checkLineId = async (lineid) =>
ajax(`/auth/checkLineId`, { lineid }, "GET");
@ -14,7 +17,7 @@ export const getUserInfo = async () =>
ajax(`/user/getUserInfo`);
export const updateUserInfo = async (params) =>
ajax(`/user/updateUserInfo`,params, 'POST');
ajax(`/user/updateUserInfo`, params, 'POST');
export const setUserLevel = async (level) =>
ajax(`/user/setUserLevel`, { level }, "POST");
@ -57,13 +60,13 @@ export const updateSendCount = async (userid) =>
//授權使用者
export const setAuthUser = async (params) =>
ajax(`/user/setAuthUser`, params , "POST");
ajax(`/user/setAuthUser`, params, "POST");
export const getAuthUsers = async () =>
ajax(`/user/getAuthUsers`);
export const delAuthUser = async (id) =>
ajax(`/user/delAuthUser`,{id});
ajax(`/user/delAuthUser`, { id });
export const getAuthList = async () =>
ajax(`/user/getAuthList`);
@ -75,7 +78,25 @@ export const getMovie = async () =>
export const getMarquee = async () =>
ajax(`/ads/getMarquee`);
export const getFlexcard = async () =>
ajax(`/ads/getFlexcard`);
//通訊錄
export const getUserFaviList = async (params) =>
ajax(`/UserFavi/getUserFaviList`, params, "POST");
export const addUserFavi = async (params) =>
ajax(`/UserFavi/addUserFavi`, params , "POST");
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,14 +1,17 @@
import ajax from "./ajax";
//通訊錄
export const getUserData = async (params) =>
ajax(`/User/getUser`, params, "POST");
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");
ajax(`/user/updateUserExtra`, params, "POST");
export const updateUserLink = async (params) =>
ajax(`/User/updateUserLink`, params, "POST");
ajax(`/user/updateUserLink`, params, "POST");
export const updateUserAddon = async (params) =>
ajax(`/User/updateUserAddon`, {nfc_addon:params}, "POST");
ajax(`/user/updateUserAddon`, {nfc_addon:params}, "POST");

@ -541,8 +541,17 @@ h1, h2, h3, h4, h5, h6 {
}
/* ========================================= 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 {
@ -704,6 +713,12 @@ h1, h2, h3, h4, h5, h6 {
object-fit: cover;
}
.bottomBtnCnt {
padding: 15px;
background: -webkit-gradient(linear, left bottom, left top, from(#b2c4ce), color-stop(80%, #b2c4ce), color-stop(90%, rgba(178, 196, 206, 0.5)), to(rgba(178, 196, 206, 0)));
background: linear-gradient(to top, #b2c4ce 0%, #b2c4ce 80%, rgba(178, 196, 206, 0.5) 90%, rgba(178, 196, 206, 0) 100%);
}
/*!
* Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 KiB

After

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 792 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

After

Width:  |  Height:  |  Size: 751 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 729 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 33 KiB

@ -4,8 +4,18 @@
/* ========================================= 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{
@ -153,6 +163,11 @@
}
}
.bottomBtnCnt{
padding: 15px;
background: linear-gradient(to top,#b2c4ce 0%,#b2c4ce 80%,rgba(178,196,206,.5) 90%,rgba(178,196,206,0) 100%);
}

@ -2,7 +2,7 @@
<div class="preview page">
<van-nav-bar
class="bg-skyBlue py-1"
@click-left="$router.push('/card/edit')"
@click-left="$router.push('/card')"
>
<template #title>
<h5 class="text-white mb-1"><strong>預覽</strong></h5>
@ -57,7 +57,7 @@ onDeactivated(() => {
.chatbox {
background-color: #333;
background-color: #000;
margin-top: 10px;
padding-top: 10px;
}

@ -4,7 +4,7 @@ import router from "./router";
import store from "./store";
import pinia from './store/pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { initStore } from './utils/initStore';
// import { initStore } from './utils/initStore';
import liff from '@line/liff';
import { VueClipboard } from "@soerenmartius/vue3-clipboard";
@ -25,7 +25,6 @@ liff.init({
vue.use(VueClipboard);
vue.use(pinia);
// 初始化Store
initStore(pinia);
vue.use(store).use(router).mount("#app");

@ -1,7 +1,5 @@
import { createRouter, createWebHistory } from "vue-router";
import store from "@/store";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
@ -51,7 +49,7 @@ const routes = [
component: Card,
children: [
{
path: "/card/edit",
path: "/card",
name: "CardEdit",
component: () =>
import("../views/Card/Edit.vue"),
@ -95,12 +93,12 @@ const routes = [
component: () => import("../views/Auth/GetAuth.vue"),
meta: { keepAlive: true },
},
{
path: "/auth/edit",
name: "AuthEdit",
component: () => import("../views/Auth/Edit.vue"),
meta: { keepAlive: true },
},
// {
// path: "/auth/edit",
// name: "AuthEdit",
// component: () => import("../views/Auth/Edit.vue"),
// meta: { keepAlive: true },
// },
{
path: "/auth/preview",
name: "AuthPreview",
@ -123,6 +121,12 @@ const routes = [
component: () =>
import("../views/Login/index.vue"),
},
{
path: "/actlogin",
name: "ActLogin",
component: () =>
import("../views/Login/actLogin.vue"),
},
{
path: "/test",
name: "Test",
@ -138,17 +142,20 @@ const router = createRouter({
router.beforeEach((to, from, next) => {
NProgress.start();
if (to.path !== "/" && to.path !== "/login" && to.path !== "/register") {
if (to.path !== "/" && to.path !== "/login" && to.path !== "/actlogin" && to.path !== "/register") {
if (!sessionStorage.getItem("token")) {
next("/");
}
console.log('to',to);
sessionStorage.setItem("redirect", to.fullPath);
sessionStorage.setItem("refer", to.query.cardid);
return next("/actlogin");
}
// if(!store.state.user.userInfo){
// await store.dispatch('user/getUserInfo')
// }
}
next();
return next();
});
router.afterEach(() => {

@ -1,17 +1,32 @@
import { defineStore } from 'pinia'
import { updateCusCard } from "@/api";
import { getCardData } from "@/api/card";
export const useCardStore = defineStore('card', {
state: () => {
return {
cusCard: '',
vipCard: '',
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) {

@ -1,13 +1,15 @@
import { defineStore } from 'pinia'
import { getUserData } from "@/api/user";
import { toggleSendWithAD } from "@/api";
import { toggleSendWithAD,setUserTpl } from "@/api";
export const useUserStore = defineStore('user', {
state: () => {
return {
userData: {
is_send_ad: 0,
nc_template: 0,
nfc_template: 0,
},
}
},
@ -29,13 +31,15 @@ export const useUserStore = defineStore('user', {
return true;
}
return false;
}
// async setUserTpl(context, payload) {
// var res = await setUserTpl(payload);
// if (res.code === 200) {
// context.commit("setTpl", payload);
// }
// },
},
async setUserTpl(payload) {
let res = await setUserTpl(payload);
if (res.code === 200) {
this.userData.nc_template = payload
return true;
}
return false;
},
},
persist: true
})

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

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

@ -7,6 +7,8 @@ function genCard(vcard) {
{
"type": "box",
"layout": "baseline",
"margin": "md",
"paddingStart": "lg",
"contents": [
{
"type": "icon",
@ -19,11 +21,9 @@ function genCard(vcard) {
"type": "text",
"text": "${vcard.url}",
"color": "#6c6664",
"size": "md"
"size": "sm"
}
],
"margin": "md",
"paddingStart": "lg"
]
},
`;
} else {
@ -31,6 +31,8 @@ function genCard(vcard) {
{
"type": "box",
"layout": "baseline",
"margin": "md",
"paddingStart": "lg",
"contents": [
{
"type": "icon",
@ -43,16 +45,14 @@ function genCard(vcard) {
"type": "text",
"text": "${vcard.url}",
"color": "#6c6664",
"size": "md",
"size": "sm",
"action": {
"type": "uri",
"label": "yahoo",
"uri": "${vcard.url}"
}
}
],
"margin": "md",
"paddingStart": "lg"
]
},
`;
}
@ -66,6 +66,8 @@ function genCard(vcard) {
{
"type": "box",
"layout": "baseline",
"margin": "md",
"paddingStart": "lg",
"contents": [
{
"type": "icon",
@ -78,20 +80,18 @@ function genCard(vcard) {
"type": "text",
"text": "${vcard.address}",
"color": "#6c6664",
"size": "md",
"size": "sm",
"wrap": true,
"action": {
"type": "uri",
"label": "action",
"uri": "https://www.google.com.tw/maps/place/${encodeURIComponent(
vcard.address
)}"
},
"wrap": true
}
}
],
"margin": "md",
"paddingStart": "lg"
}
]
},
`;
} else {
vcardAddr = "";
@ -104,6 +104,8 @@ function genCard(vcard) {
{
"type": "box",
"layout": "baseline",
"margin": "md",
"paddingStart": "lg",
"contents": [
{
"type": "icon",
@ -116,16 +118,14 @@ function genCard(vcard) {
"type": "text",
"text": "${vcard.tel}",
"color": "#6c6664",
"size": "md",
"size": "sm",
"action": {
"type": "uri",
"label": "action",
"uri": "tel:${vcard.tel}"
}
}
],
"margin": "md",
"paddingStart": "lg"
]
},
`;
} else {
@ -138,13 +138,22 @@ function genCard(vcard) {
vcardPhone = `
{
"type": "box",
"layout": "vertical",
"layout": "baseline",
"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": "xxl",
"color": "#93476e",
"size": "sm",
"color": "#6c6664",
"action": {
"type": "uri",
"label": "action",
@ -168,6 +177,8 @@ function genCard(vcard) {
"size": "full",
"aspectRatio": "1:1",
"aspectMode": "cover",
"align": "center",
"gravity": "center",
"action": {
"type": "uri",
"label": "action",
@ -186,6 +197,8 @@ function genCard(vcard) {
{
"type": "box",
"layout": "baseline",
"margin": "md",
"paddingStart": "lg",
"contents": [
{
"type": "icon",
@ -205,9 +218,7 @@ function genCard(vcard) {
"uri": "mailto:${vcard.email}"
}
}
],
"margin": "md",
"paddingStart": "lg"
]
},
`;
} else {
@ -227,74 +238,30 @@ function genCard(vcard) {
"body": {
"type": "box",
"layout": "vertical",
"height": "290px",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [],
"height": "45%"
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "image",
"size": "full",
"position": "relative",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-03h.png"
}
],
"height": "55%"
"type": "image",
"size": "full",
"position": "relative",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-03h.png",
"aspectRatio": "4:1",
"aspectMode": "cover"
}
],
"height": "100%",
"position": "absolute",
"width": "100%"
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "Company",
"size": "3xl",
"weight": "bold",
"offsetBottom": "md",
"color": "#c6b0c9"
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "${vcard.company}",
"color": "#ffffff",
"size": "md"
}
],
"backgroundColor": "#6c6d8b",
"paddingTop": "sm",
"paddingBottom": "sm",
"paddingStart": "lg",
"cornerRadius": "xxl",
"paddingEnd": "lg",
"offsetBottom": "xl"
}
],
"cornerRadius": "15px",
"paddingStart": "10px",
"paddingEnd": "10px",
"alignItems": "flex-end",
"offsetEnd": "none",
"position": "absolute",
"offsetTop": "none"
"width": "100%",
"justifyContent": "flex-end",
"height": "100%",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}"
}
},
{
"type": "box",
@ -307,62 +274,65 @@ function genCard(vcard) {
{
"type": "box",
"layout": "vertical",
"contents": [${vcardAvatar}],
"cornerRadius": "10px",
"margin": "none",
"width": "100%"
"contents": [
${vcardAvatar}
],
"width": "90px",
"cornerRadius": "xl"
},
{
"type": "box",
"layout": "vertical",
"justifyContent": "space-between",
"width": "80%",
"contents": [
{
"type": "button",
"action": {
"type": "uri",
"label": "加入好友",
"uri": "http://linecorp.com/"
"uri": "https://line.naver.jp/ti/p/~${vcard.line}"
},
"color": "#755483",
"height": "sm",
"style": "primary",
"margin": "md"
"margin": "xs"
},
{
"type": "button",
"action": {
"type": "uri",
"label": "分享名片",
"uri": "http://linecorp.com/"
"uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1&tpl=1"
},
"color": "#93476e",
"height": "sm",
"style": "primary",
"margin": "md"
"margin": "xs"
},
{
"type": "button",
"action": {
"type": "uri",
"label": "其他連結",
"uri": "http://linecorp.com/"
"label": "收藏名片",
"uri": "https://liff.line.me/${import.meta.env.VITE_APP_LINE_LIFF_ID}/address?act=add&cardid=${vcard.user_id}"
},
"color": "#c73f6d",
"height": "sm",
"style": "primary",
"margin": "md"
"margin": "xs"
}
],
"margin": "xxl"
}
],
"paddingTop": "5%",
"paddingBottom": "8%",
"justifyContent": "flex-start",
"width": "30%",
"paddingBottom": "5%",
"justifyContent": "space-between",
"width": "35%",
"alignItems": "center",
"height": "95%"
"height": "100%",
"position": "relative"
},
{
"type": "box",
@ -370,20 +340,46 @@ function genCard(vcard) {
"contents": [
{
"type": "box",
"layout": "horizontal",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "Company",
"size": "3xl",
"weight": "bold",
"color": "#c6b0c9",
"offsetBottom": "sm",
"offsetEnd": "md"
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "${vcard.name}",
"size": "xxl",
"weight": "bold"
"text": "${vcard.company}",
"color": "#ffffff",
"size": "md"
}
]
},
],
"backgroundColor": "#6c6d8b",
"paddingTop": "sm",
"paddingBottom": "sm",
"paddingStart": "lg",
"cornerRadius": "xxl",
"paddingEnd": "lg",
"position": "absolute",
"offsetTop": "xxl"
}
],
"cornerRadius": "15px",
"alignItems": "flex-end",
"position": "relative"
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "box",
"layout": "vertical",
@ -393,17 +389,25 @@ function genCard(vcard) {
"text": "${vcard.title}",
"size": "md",
"weight": "bold",
"color": "#888888",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=1"
}
"color": "#888888"
}
]
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "${vcard.name}",
"size": "xxl",
"weight": "bold"
}
]
}
],
"alignItems": "center"
"alignItems": "flex-start",
"justifyContent": "space-between"
},
{
"type": "separator",
@ -414,33 +418,51 @@ function genCard(vcard) {
"type": "box",
"layout": "vertical",
"contents": [
${vcardPhone}
${vcardTel}
${vcardPhone}
${vcardLink}
${vcardEmail}
${vcardAddr}
${vcardEmail}
${vcardAddr}
{
"position": "absolute",
"width": "1px",
"height": "1px",
"backgroundColor": "#333333",
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "separator"
}
]
}
],
"margin": "xs"
"margin": "xs",
"backgroundColor": "#ffffff95",
"paddingTop": "sm",
"paddingBottom": "lg"
}
],
"height": "84%",
"paddingStart": "xxl"
"height": "100%",
"position": "relative",
"width": "65%",
"paddingStart": "lg",
"paddingEnd": "md",
"paddingBottom": "lg"
}
],
"paddingAll": "xl",
"height": "100%",
"alignItems": "flex-end"
"alignItems": "flex-start"
}
],
"paddingAll": "0px",
"justifyContent": "center",
"alignItems": "center",
"action": {
"type": "uri",
"label": "action",
"uri": "https://utel.zltest.com.tw/card/?params=i7Kq7O59hPX1MJ%2Bqd8zQKBwuyc%2F%2BZ%2BZs%2BZXtXBy4zvg%3D&cardid=1"
},
"justifyContent": "center",
"alignItems": "center",
"height": "420px"
"uri": "${vcard.nfcurl}&cardid=2"
}
}
}
}

@ -46,7 +46,7 @@ function genCard(vcard) {
},
"wrap": true,
"align": "end"
}
},
`;
} else {
vcardAddr = "";
@ -146,12 +146,14 @@ function genCard(vcard) {
"body": {
"type": "box",
"layout": "vertical",
"height": "290px",
"contents": [
{
"position": "absolute",
"type": "image",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-02.png",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-02h.png",
"size": "full",
"position": "absolute",
"aspectRatio": "2:3",
"aspectMode": "cover"
},
{
@ -226,11 +228,11 @@ function genCard(vcard) {
"type": "box",
"layout": "vertical",
"contents": [${vcardAvatar}],
"cornerRadius": "150px",
"cornerRadius": "20px",
"borderWidth": "bold",
"borderColor": "#ffffff",
"margin": "none",
"width": "30%"
"width": "100px"
}
],
"alignItems": "center",
@ -252,7 +254,20 @@ function genCard(vcard) {
${vcardTel}
${vcardLink}
${vcardEmail}
${vcardAddr}
${vcardAddr}
{
"position": "absolute",
"width": "1px",
"height": "1px",
"backgroundColor": "#333333",
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "separator"
}
]
}
],
"alignItems": "flex-end",
"paddingEnd": "xl"
@ -267,9 +282,9 @@ function genCard(vcard) {
"action": {
"type": "uri",
"label": "加入好友",
"uri": "http://linecorp.com/"
"uri": "https://line.naver.jp/ti/p/~${vcard.line}"
},
"color": "#6c6664",
"color": "#464757",
"height": "sm",
"style": "primary"
},
@ -278,15 +293,27 @@ function genCard(vcard) {
"action": {
"type": "uri",
"label": "分享名片",
"uri": "http://linecorp.com/"
"uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1&tpl=2"
},
"color": "#6c6664",
"color": "#464757",
"height": "sm",
"margin": "sm",
"style": "primary"
},
{
"type": "button",
"action": {
"type": "uri",
"label": "收藏名片",
"uri": "https://liff.line.me/${import.meta.env.VITE_APP_LINE_LIFF_ID}/address?act=add&cardid=${vcard.user_id}"
},
"color": "#464757",
"height": "sm",
"margin": "sm",
"style": "primary"
}
],
"width": "30%"
"width": "100px"
}
],
"alignItems": "flex-end"
@ -299,39 +326,41 @@ function genCard(vcard) {
"height": "92%",
"borderWidth": "light",
"borderColor": "#bbbbbb",
"paddingAll": "10px",
"paddingAll": "5px",
"justifyContent": "space-between",
"cornerRadius": "lg"
},
{
"position": "absolute",
"type": "box",
"layout": "vertical",
"layout": "vertical",
"height": "25px",
"justifyContent": "center",
"alignItems": "center",
"paddingStart": "lg",
"paddingEnd": "lg",
"offsetTop": "sm",
"offsetStart": "sm",
"cornerRadius": "15px",
"backgroundColor": "#ffffff",
"contents": [
{
"type": "text",
"text": "匯康科技",
"text": "${vcard.company}",
"color": "#e5b164",
"size": "md"
}
],
"position": "absolute",
"offsetTop": "sm",
"offsetStart": "sm",
"backgroundColor": "#ffffff",
"cornerRadius": "15px",
"paddingStart": "10px",
"paddingEnd": "10px"
]
}
],
"paddingAll": "0px",
"justifyContent": "center",
"alignItems": "center",
"action": {
"type": "uri",
"label": "action",
"uri": "https://utel.zltest.com.tw/card/?params=i7Kq7O59hPX1MJ%2Bqd8zQKBwuyc%2F%2BZ%2BZs%2BZXtXBy4zvg%3D&cardid=1"
},
"height": "280px",
"justifyContent": "center",
"alignItems": "center"
"uri": "${vcard.nfcurl}&cardid=3"
}
}
}
}

@ -79,14 +79,12 @@ function genCard(vcard) {
"type": "text",
"text": "${vcard.tel}",
"color": "#ffffff",
"size": "sm",
"size": "lg",
"wrap": true,
"action": {
"type": "uri",
"label": "action",
"uri": "https://www.google.com.tw/maps/place/${encodeURIComponent(
vcard.address
)}"
"uri": "tel:${vcard.tel}"
}
},
`;
@ -146,50 +144,109 @@ function genCard(vcard) {
"body": {
"type": "box",
"layout": "horizontal",
"height": "290px",
"paddingAll": "0px",
"backgroundColor": "#353e45",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}"
},
"contents": [
{
"position": "absolute",
"type": "box",
"layout": "vertical",
"width": "67%",
"height": "100%",
"justifyContent": "flex-start",
"offsetEnd": "none",
"contents": [
{
"position": "relative",
"type": "image",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-01s.png",
"size": "full",
"aspectRatio": "3:1",
"offsetTop": "15%"
}
]
},
{
"position": "relative",
"type": "box",
"layout": "vertical",
"width": "35%",
"height": "100%",
"paddingAll": "14px",
"justifyContent": "space-between",
"alignItems": "center",
"backgroundColor": "#ffffff",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [${vcardAvatar}],
"cornerRadius": "150px",
"width": "60%",
"borderWidth": "bold",
"borderColor": "#f5c520",
"margin": "none"
},
{
"type": "text",
"text": "${vcard.name}",
"size": "xl",
"weight": "bold",
"margin": "md"
"contents": [
{
"type": "box",
"layout": "vertical",
"width": "80%",
"margin": "none",
"borderWidth": "bold",
"borderColor": "#f5c520",
"cornerRadius": "150px",
"contents": [${vcardAvatar}]
},
{
"type": "text",
"text": "${vcard.name}",
"size": "xl",
"weight": "bold",
"margin": "md"
},
{
"type": "text",
"text": "${vcard.title}",
"size": "md",
"weight": "regular",
"color": "#666666"
},
${vcardPhone}
]
},
{
"type": "text",
"text": "${vcard.title}",
"size": "md",
"weight": "regular",
"color": "#666666",
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "text",
"text": "收藏名片"
}
],
"position": "relative",
"height": "40px",
"borderWidth": "light",
"borderColor": "#333333",
"cornerRadius": "lg",
"justifyContent": "center",
"alignItems": "center",
"width": "100%",
"action": {
"type": "uri",
"label": "action",
"uri": "${vcard.nfcurl}&cardid=1"
}
},
${vcardPhone}
],
"alignItems": "center",
"paddingTop": "5%",
"paddingBottom": "5%",
"width": "35%"
"uri": "https://liff.line.me/${import.meta.env.VITE_APP_LINE_LIFF_ID}/address?act=add&cardid=${vcard.user_id}"
}
}
]
},
{
"position": "relative",
"type": "box",
"layout": "vertical",
"width": "66%",
"height": "100%",
"justifyContent": "space-between",
"paddingAll": "14px",
"contents": [
{
"type": "box",
@ -207,7 +264,7 @@ function genCard(vcard) {
},
{
"type": "box",
"layout": "vertical",
"layout": "vertical",
"contents": [
${vcardLink}
${vcardEmail}
@ -216,89 +273,61 @@ function genCard(vcard) {
"type": "box",
"layout": "horizontal",
"justifyContent": "space-between",
"margin": "md",
"contents": [
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "button",
"action": {
"type": "uri",
"label": "加入好友",
"uri": "http://linecorp.com/"
},
"color": "#dddddd",
"height": "sm",
"style": "link"
}
],
"width": "48%",
"height": "40px",
"justifyContent": "center",
"alignItems": "center",
"borderWidth": "light",
"borderColor": "#dddddd",
"cornerRadius": "lg",
"width": "48%",
"height": "36px"
"cornerRadius": "lg",
"contents": [
{
"type": "text",
"text": "加入好友",
"color": "#dddddd"
}
],
"action": {
"type": "uri",
"label": "action",
"uri": "https://line.naver.jp/ti/p/~${vcard.line}"
}
},
{
"type": "box",
"layout": "vertical",
"layout": "vertical",
"width": "48%",
"height": "40px",
"justifyContent": "center",
"alignItems": "center",
"borderWidth": "light",
"borderColor": "#dddddd",
"cornerRadius": "lg",
"contents": [
{
"type": "button",
"action": {
"type": "uri",
"label": "分享名片",
"uri": "http://linecorp.com/"
},
"color": "#dddddd",
"height": "sm",
"style": "link"
}
{
"type": "text",
"text": "分享名片",
"color": "#dddddd"
}
],
"cornerRadius": "lg",
"borderColor": "#dddddd",
"borderWidth": "light",
"height": "36px",
"width": "48%"
"action": {
"type": "uri",
"label": "action",
"uri": "${import.meta.env.VITE_APP_SEND_URL}/?userid=${vcard.user_id}&cardid=1&tpl=3"
}
}
],
"margin": "md"
]
}
]
}
],
"backgroundColor": "#353e45",
"paddingBottom": "4%",
"paddingStart": "5%",
"paddingEnd": "5%",
"width": "66%",
"justifyContent": "space-between",
"paddingTop": "4%"
},
{
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "image",
"url": "https://369cycle.zltest.com.tw/tggo/template/bg-01.png",
"size": "full"
}
],
"position": "absolute",
"width": "67%",
"height": "70%",
"offsetEnd": "none",
"justifyContent": "flex-end"
}
],
"paddingAll": "0px",
"action": {
"type": "uri",
"label": "action",
"uri": "https://utel.zltest.com.tw/card/?params=i7Kq7O59hPX1MJ%2Bqd8zQKBwuyc%2F%2BZ%2BZs%2BZXtXBy4zvg%3D&cardid=1"
},
"height": "270px"
]
}
]
}
}
}

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

@ -1,5 +1,7 @@
import _ from "lodash";
const DEFAULT_LINK = 'https://utel.vip';
function vcardUuid(vcard, secret) {
const hash = CryptoJS.HmacMD5(JSON.stringify(vcard), secret);
const hex = CryptoJS.enc.Hex.stringify(hash);
@ -28,7 +30,6 @@ function renderCard(ctx) {
let rCard = {
type: "bubble",
hero: {
animated: true,
aspectMode: "cover",
aspectRatio: card.ratio || "20:13",
size: "full",
@ -95,9 +96,9 @@ function genCard1(ctx) {
altText: vcard.altText,
contents: {
type: "carousel",
contents: _.map(vcard.cards, (card, cardIdx) =>
renderCard({ ...ctx, card, cardIdx })
),
contents: vcard.cards
.filter(card => card.isSend === true)
.map((card, cardIdx) => renderCard({ ...ctx, card, cardIdx }))
},
};
}

@ -1,12 +1,5 @@
import { useCardStore } from '@/store/card.js';
import { getCardData } from '@/api/card.js';
// import { useCardStore } from '@/store/card.js';
// import { getCardData } from '@/api/card.js';
export const initStore = async (pinia) => {
const cardStore = useCardStore();
let res = await getCardData();
if (res.code === 200) {
cardStore.cusCard = res.data.cus_card;
cardStore.vipCard = res.data.vip_card;
}
};
// export const initStore = async (pinia) => {
// };

@ -1,50 +1,759 @@
<script setup>
import liff from "@line/liff";
import _ from 'lodash';
import { onMounted, onBeforeMount, ref , watch } from 'vue'
import { toClipboard } from "@soerenmartius/vue3-clipboard";
import { showToast, showSuccessToast, showConfirmDialog,showFailToast } from 'vant';
import { useRoute } from 'vue-router';
import { showToast,showSuccessToast } from 'vant';
import {
getUserFaviList
, getUserCateList
, updateUserCate
, setUserFaviCate
, addUserFavi
, deleteUserFavi
} from '@/api'
import { onMounted, reactive, ref, toRefs, computed, watch } from 'vue'
import { getFaviLogs, addFaviLog ,deleteFaviLog,updateFaviLog } from '@/api/faviLog'
import { getAreaList } from '@/api/system';
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([]);
const showFaviLog = ref(false);
onMounted(async () => {
if (route.query.act === 'add') {
let res = await addUserFavi({ uf_user_id: route.query.cardid });
if (res.code === 445) {
showToast('您為基本型用戶僅能最多收藏10人');
}
}
initData();
getCateList();
});
const initData = async () => {
let res = await getUserFaviList(search.value);
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 doCopy = (text) => {
toClipboard(text);
showToast("已放入剪貼簿");
};
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) => {
search.value.cate = value.selectedValues[1]
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 {
showToast('更新失敗')
}
};
const search = ref({
cate: 0,
area: 0,
sex: 2,
keyword: ''
});
const tab2showPicker = ref(false);
const tab3showPicker = ref(false)
const tab3columns = ref([])
const areaName = ref('')
//
let areaRes = await getAreaList()
if (areaRes.code === 200) {
tab3columns.value = areaRes.data
// tab3columns
tab3columns.value.unshift({
text: '全部',
value: 0
})
//
// if (areaRes.data.length > 0) {
// const findRes = _.find(areaRes.data, { value: form.value.area })
// if (findRes) {
// areaName.value = findRes.text
// }
// }
}
const tab3OnConfirm = (value) => {
areaName.value = value.selectedOptions[0].text
search.value.area = value.selectedOptions[0].value
tab3showPicker.value = false
}
const tab4showPicker = ref(false);
const tab4columns = ref([
{
text: '全部',
value: 2
},
{
text: '男',
value: 1
},
{
text: '女',
value: 0
}
]);
const sexName = ref('')
const tab4OnConfirm = (value) => {
sexName.value = value.selectedOptions[0].text
search.value.sex = value.selectedOptions[0].value
tab4showPicker.value = false
}
const handleSearch = async () => {
let res = await getUserFaviList(search.value);
if (res.code === 200) {
addressList.value = res.data;
}
}
// START:
const faviLogId = ref(0) // id
const faviLogMsg = ref('') //
const faviLogList = ref([]) //
const faviLogEditId = ref(0) // id
const handleFaviLog = (id) => {
showFaviLog.value = true
faviLogId.value = id
}
watch(faviLogId, async (val) => {
if (val > 0) {
//
loadFaviLog()
}
})
const loadFaviLog = async () => {
let res = await getFaviLogs(faviLogId.value)
if(res.code === 200){
faviLogList.value = res.data
}
}
const handleAddFaviLog = async () => {
let res = await addFaviLog({ uf_id: faviLogId.value, note: faviLogMsg.value })
if(res.code === 200){
showToast('新增成功')
faviLogMsg.value = ''
loadFaviLog()
}else{
showFailToast('新增失敗')
}
}
const handleDeleteFaviLog = async (id) => {
let res = await deleteFaviLog(id)
if(res.code === 200){
showToast('刪除成功')
loadFaviLog()
}else{
showFailToast('刪除失敗')
}
}
const handleEditFaviLog = async (item) => {
let res = await updateFaviLog(item)
if(res.code === 200){
showToast('更新成功')
faviLogEditId.value = 0
// loadFaviLog()
}else{
showFailToast('更新失敗')
}
}
const handleCloseFaviLog = () => {
faviLogId.value = 0
faviLogMsg.value = ''
showFaviLog.value = false
}
const formatNote = (note) => {
//
const emailRegex = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi;
// , 0983214434
const phoneRegex = /(0[2-9]\d{7,8}|09\d{8})/g;
//
const urlRegex = /(https?:\/\/[^\s]+)/g;
let formattedNote = note
.replace(emailRegex, '<a href="mailto:$1">$1</a>')
.replace(phoneRegex, '<a href="tel:$1">$1</a>')
.replace(urlRegex, '<a href="$1" target="_blank">$1</a>');
return formattedNote;
};
// END:
</script>
<template>
<div class="member page">
<van-nav-bar
class="bg-skyBlue py-1"
left-arrow
right-arrow
@click-left="$router.push('/')"
@click-right="setShowPicker = true"
>
<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>
<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-sliders text-white" :style="{opacity:0.5}"></i></h4>
<h4><i class="fa-solid fa-gear text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
</van-nav-bar>
<van-popup v-model:show="setShowPicker" position="bottom">
<van-picker
:columns="setColumns"
@confirm="setConfirm"
@cancel="setShowPicker = false"
/>
</van-popup>
<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>
<van-cell-group inset>
<van-row gutter="0" align="center">
<van-col span="5">
<van-field v-model="areaName" is-link readonly name="picker" :border="false" placeholder="縣市"
@click="tab3showPicker = true" />
<van-popup v-model:show="tab3showPicker" position="bottom">
<van-picker confirm-button-text="" cancel-button-text="" :columns="tab3columns"
@confirm="tab3OnConfirm" @cancel="tab3showPicker = false" />
</van-popup>
</van-col>
<van-col span="5">
<van-field v-model="sexName" is-link readonly name="picker" :border="false" placeholder="性別"
@click="tab4showPicker = true" />
<van-popup v-model:show="tab4showPicker" position="bottom">
<van-picker confirm-button-text="" cancel-button-text="" :columns="tab4columns"
@confirm="tab4OnConfirm" @cancel="tab4showPicker = false" />
</van-popup>
</van-col>
<van-col span="14">
<van-search v-model="search.keyword" show-action placeholder="請輸入搜尋關鍵字" @search="handleSearch">
<template #action>
<van-button class="btn-darkBlue" @click="handleSearch">
搜索
</van-button>
</template>
</van-search>
</van-col>
</van-row>
</van-cell-group>
<!-- END: 通訊錄類別 -->
<van-cell-group inset>
<van-list>
<div class="list-item" style="font-weight: 700;">
<div class="left">
電子名片
</div>
<div class="right">
分類/紀錄/刪除
</div>
</div>
<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" @click="handleFaviLog(item.uf_id)">
<h5><i class="fa-solid fa-share-nodes text-darkBlue"></i></h5>
</van-button>
<van-button size="small" class="border-0" @click="handleDeleteFavi(item.uf_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>
<!-- START: 往來紀錄 -->
<van-popup v-model:show="showFaviLog" round closeable position="bottom" @close="handleCloseFaviLog" :style="{ height: '90%' }">
<div style="padding-top: 50px;border: 1px;height: 100%;" class="content">
<!-- 好友往來紀錄 -->
<van-cell-group inset>
<van-field v-model="faviLogMsg" center label="往來紀錄" placeholder="請輸入往來紀錄">
<template #button>
<van-button size="small" class="btn-darkBlue" @click="handleAddFaviLog"></van-button>
</template>
</van-field>
</van-cell-group>
<van-cell-group inset>
<van-steps direction="vertical">
<van-step v-for="item in faviLogList" :key="item.id">
<div class="favi-log">
<div class="title">
<div class="left">
<h5>{{ item.create_time }}</h5>
</div>
<div class="right">
<van-button size="small" plain type="primary" @click="faviLogEditId = item.id">修改</van-button>
&nbsp;
<van-button size="small" type="danger" @click="handleDeleteFaviLog(item.id)"></van-button>
</div>
</div>
<div class="body">
<template v-if="faviLogEditId === item.id">
<van-field v-model="item.note" center>
<template #button>
<van-button size="small" type="primary" @click="handleEditFaviLog(item)"></van-button>
</template>
</van-field>
</template>
<template v-else>
<p v-html="formatNote(item.note)"></p>
</template>
</div>
</div>
</van-step>
</van-steps>
</van-cell-group>
</div>
</van-popup>
<!-- END: 往來紀錄 -->
</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;
}
}
}
.favi-log {
.title {
display: flex;
.left {
flex: 1 0 0%;
}
.right {
width: 100px;
}
}
.body {
padding: 10px;
:deep(a) {
color: #1989fa;
text-decoration: none;
}
}
}
.address-block {
max-height: 80vh;
overflow-y: auto;
}
:deep(.van-popup__close-icon) {
color: #fff !important;
}
</style>

@ -1,46 +1,3 @@
<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>
import { onMounted, ref } from 'vue'
@ -99,15 +56,79 @@ onMounted(()=>{
</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>
#auth-list{
width: 100%;
td,th{
border: 1px solid #ddd;
padding: 3px;
table#auth-list{
width: 100%;
thead th{
color: #fff;
background-color: #4a677d;
}
tr:nth-child(even){
background-color: #f2f2f2;
}
th,td{
padding: 5px 10px;
}
}
tr:nth-child(even){
background-color: #f2f2f2;
}
}
</style>

File diff suppressed because it is too large Load Diff

@ -1,22 +1,3 @@
<template>
<div>
<van-nav-bar title="代客編輯商務卡片" right-text="" @click-right="$router.push('/')" />
<table id="auth-list">
<tr>
<th>授權會員</th>
<th>授權時間</th>
<th>操作</th>
</tr>
<tr v-for="v of authList" :key="v.id">
<td>{{v.user_id}}</td>
<td>{{v.auth_time}}</td>
<td @click="handleEdit(v.user_id)"></td>
</tr>
</table>
</div>
</template>
<script setup>
import { onMounted , ref } from "vue";
@ -33,20 +14,59 @@ onMounted(async()=>{
})
const handleEdit = (user_id)=>{
router.push({path:'/auth/edit',query:{user_id: user_id}});
router.push({path:'/card',query:{user_id: user_id}});
}
</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="handleEdit(v.user_id)"></td>
</tr>
</tbody>
</table>
</van-cell-group>
</div>
</div>
</template>
<style src="@/assets/css/main.css"></style>
<style lang="less" scoped>
#auth-list{
width: 100%;
td,th{
border: 1px solid #ddd;
padding: 3px;
}
tr:nth-child(even){
background-color: #f2f2f2;
table#auth-list{
width: 100%;
thead th{
color: #fff;
background-color: #4a677d;
}
tr:nth-child(even){
background-color: #f2f2f2;
}
th,td{
padding: 5px 10px;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

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

@ -6,13 +6,12 @@ import { toClipboard } from "@soerenmartius/vue3-clipboard";
import { ref, computed, onBeforeMount } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useUserStore } from '@/store/user';
import { useCardStore } from '@/store/card';
import { showToast, showSuccessToast, showConfirmDialog } from "vant";
import 'vant/es/toast/style';
import { Dialog } from "vant";
import { login, bindCard, getMovie, getMarquee } from "@/api";
import { login, bindCard, getMovie, getMarquee, bindUser } from "@/api";
import noUserImg from '@/assets/images/upload.jpg'
@ -20,15 +19,40 @@ const router = useRouter();
const route = useRoute();
const userStore = useUserStore();
const cardStore = useCardStore();
const showShare = ref(false);
const showNfcQrcode = ref(false);
const showQrcode = ref(false);
const checked = ref(true);
const imageUrl = ref(import.meta.env.VITE_APP_BASE_URL);
const is_due = ref(false);
async function handleBindCard(uid, verify) {
//
showConfirmDialog({
title: "卡片綁定",
message: "確認是否綁定這張卡片",
confirmButtonText: "確認",
cancelButtonText: "取消",
})
.then(async () => {
//
let bindRes = await bindCard({
uid,
verify,
});
if (bindRes.code === 200) {
showSuccessToast("綁定成功");
} else {
showFailToast("綁定失敗");
}
})
.catch(() => { });
}
onBeforeMount(async () => {
const liff = window.liff;
try {
@ -39,7 +63,7 @@ onBeforeMount(async () => {
router.push("/login");
}
if (!sessionStorage.getItem("token")) {
if (!sessionStorage.getItem("token")) { //
const profile = await liff.getProfile();
const id_token = liff.getIDToken();
@ -48,49 +72,57 @@ onBeforeMount(async () => {
if (loginRes.code === 200) {
if (route.query.act === "openright") {
showToast("您已經是本站會員");
if (route.query.verify) {
handleBindCard(loginRes.data.uid,route.query.verify);
}
}
sessionStorage.setItem("token", loginRes.data.token);
sessionStorage.setItem("uid", loginRes.data.uid);
} else if (loginRes.code === 202) {
} 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(() => { });
handleBindCard(loginRes.data.uid,route.query.verify);
}
}
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) {
} else if (loginRes.code === 201) { //
if (route.query.act === "openright") { //
if (route.query.verify) { //
router.push({
path: "/register",
query: {
verify: route.query.verify,
user_id: route.query.user_id,
},
});
return;
} else if (route.query.user_id) { //lineid
//
showConfirmDialog({
title: "會員綁定",
message: "確認是否綁定會員",
confirmButtonText: "確認",
cancelButtonText: "取消",
})
.then(async () => {
//
let bindRes = await bindUser({
line_id: profile.userId,
user_id: route.query.user_id,
});
if (bindRes.code === 200) {
showSuccessToast("綁定成功");
} else {
showFailToast("綁定失敗");
return;
}
})
.catch(() => { });
}
} else if (route.query.aid) {
} else if (route.query.aid) { //
router.push({
path: "/register",
query: {
@ -110,9 +142,10 @@ onBeforeMount(async () => {
router.push("/login");
}
}
await userStore.getUserData();
await cardStore.getCardData();
handleAD();
});
@ -132,32 +165,28 @@ const noticeClick = (num) => {
};
const handleAD = async () => {
if (userInfo.value.status === 0) {
let res;
res = await getMarquee();
if (res.code === 200) {
noticeData.value = res.data;
}
if(userInfo.value.status === 1){
return;
}
let res;
res = await getMarquee();
if (res.code === 200) {
noticeData.value = res.data;
}
res = await getMovie();
if (res.code === 200) {
adData.value = res.data;
if (sessionStorage.getItem("isAdShow") == null) {
popShow.value = true;
res = await getMovie();
if (res.code === 200) {
// res.dataObject
if (Object.keys(res.data).length !== 0) {
adData.value = res.data;
popShow.value = true;
}
}
}
};
// sessionStorage.setItem("isAdShow",false);
const popShow = ref(false);
const modalClose = ref(false);
const closeShow = () => {
sessionStorage.setItem("isAdShow", userInfo.value.level_name);
modalClose.value = true;
};
@ -175,6 +204,7 @@ const onUpdateValue = (newValue) => {
cancelButtonText: "取消",
}).then(() => {
let res = userStore.setSendWithAd(newValue)
console.log('aaa', userInfo.value.is_send_ad)
}).catch(() => {
// on cancel
@ -206,7 +236,7 @@ const goCardEdit = () => {
if (userInfo.value.level < 2) {
router.push("/card/notice");
} else {
router.push("/card/edit");
router.push("/card");
}
};
@ -215,6 +245,10 @@ const onSelect = (option) => {
showShare.value = false;
};
const handleShow = () => {
showQrcode.value = true;
};
const handleShowNfc = () => {
showNfcQrcode.value = true;
};
@ -230,17 +264,20 @@ const doCopyUid = () => {
};
const doShare = () => {
toClipboard(`https://liff.line.me/${import.meta.env.VITE_APP_LINE_LIFF_ID}/?aid=${userInfo.value.user_id}`)
toClipboard(`https://liff.line.me/${import.meta.env.VITE_APP_LINE_LIFF_ID}/?aid=${userInfo.value.agent_code}`)
showToast("已放入剪貼簿");
};
const bindTggo = () => {
let url;
if (userInfo.value.uniqid) {
let url = `https://www.tggo.com.tw/u.cgi?&mnm=mybinding&ncode=${userInfo.value.uniqid}&name=${userInfo.value.real_name}&openExternalBrowser=1`;
window.open(url, "_blank");
return;
url = `https://www.tggo.com.tw/u.cgi?&mnm=mybinding&ncode=${userInfo.value.uniqid}&name=${userInfo.value.real_name}&openExternalBrowser=1`;
} else {
url = `https://www.tggo.com.tw/u.cgi?user=1111&from=portal&openExternalBrowser=1`;
}
showToast('您的帳號尚未綁定感應卡');
window.open(url, "_blank");
return;
// showToast('');
};
const handleLogout = () => {
@ -249,7 +286,6 @@ const handleLogout = () => {
}
sessionStorage.removeItem("token");
sessionStorage.removeItem("uid");
sessionStorage.removeItem("isAdShow");
router.push("/login");
};
@ -264,15 +300,20 @@ const handleLogout = () => {
<h5 class="text-gray">歡迎來到會員中心</h5>
</a>
</template>
<template #right>
<template #left>
<div class="btn btn-sm text-skyBlue" @click="handleLogout">
<h4><i class="fa fa-sign-out" aria-hidden="true"></i></h4>
<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 !== 1">
<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)">
@ -294,11 +335,11 @@ const handleLogout = () => {
<h5 class="conpany">{{ userInfo.company }}</h5>
</div>
</div>
<div class="right">
<!-- <div class="right">
<div class="btn btn-sm text-darkBlue" @click="doShare">
<h4><i class="fa-solid fa-share-from-square"></i></h4>
<h4><i class="fa-solid fa-clone"></i></h4>
</div>
</div>
</div> -->
</div>
<div class="recommend">
@ -317,12 +358,12 @@ const handleLogout = () => {
</div>
</div>
<div class="bwtFlex px-3 mb-2">
<!-- <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> -->
<div class="content" v-if="userInfo">
<van-cell-group inset>
@ -343,15 +384,25 @@ const handleLogout = () => {
<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" readonly>
<template #label><i class="fa-solid fa-fw fa-qrcode"></i> QRcode</template>
<template #button><van-button size="small" class="bg-darkBlue text-white border-0"
@click="handleShowNfc">開啟掃描</van-button></template>
<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" readonly>
<template #label><i class="fa-solid fa-fw fa-link"></i> 名片連結</template>
<template #button><van-button size="small" class="bg-tomatoRed text-white border-0"
@click="doCopy">複製連結</van-button></template>
<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>
@ -374,7 +425,7 @@ const handleLogout = () => {
</van-cell-group>
<van-cell-group inset>
<van-field input-align="right" class="longText" readonly>
<!-- <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')">
@ -389,8 +440,8 @@ const handleLogout = () => {
編輯
</van-button>
</template>
</van-field>
<van-field input-align="right" class="longText" readonly>
</van-field> -->
<van-field input-align="right" class="longText" readonly v-if="userInfo.uniqid">
<template #label><i class="fa-solid fa-fw fa-award"></i> 綁定UTel淘金購會員</template>
<template #button>
<van-button size="small" @click="bindTggo">
@ -407,16 +458,25 @@ const handleLogout = () => {
</van-field>
</van-cell-group>
<div class="px-3">
<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>
<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>
</div>
<van-dialog v-model:show="showNfcQrcode" title="電子名片二維碼" :show-cancel-button="true" cancel-button-text=""
<van-dialog v-model:show="showQrcode" title="會員加入分享" :show-cancel-button="true" cancel-button-text=""
:show-confirm-button="false">
<div class="qrcode text-center pt-3">
<qrcode-vue :value="userInfo.referurl" :size="200" level="M" />
</div>
</van-dialog>
<van-dialog v-model:show="showNfcQrcode" title="NFC名片分享" :show-cancel-button="true" cancel-button-text=""
:show-confirm-button="false">
<div class="qrcode text-center pt-3">
<qrcode-vue :value="userInfo.nfcurl" :size="200" level="M" />

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

@ -122,7 +122,7 @@ const onSubmit = () => {
<van-field
v-model="item.name"
name=""
maxlength="10"
maxlength="15"
placeholder="請輸入您的連結名稱"
:rules="[{ required: true, message: '連結名稱必填' }]"
/>

@ -134,7 +134,7 @@ const onSubmit = async () => {
}
};
const activeCollapse = ref(1);
const activeCollapse = ref("1");
</script>
<template>
@ -173,8 +173,8 @@ const activeCollapse = ref(1);
v-model="form.mark"
rows="3"
type="textarea"
maxlength="100"
placeholder="請輸入100字以內的簡介"
maxlength="200"
placeholder="請輸入200字以內的簡介"
show-word-limit
:style="{ border: '1px #e3e3e3 solid', borderRadius: '6px' }"
/>
@ -343,7 +343,7 @@ const activeCollapse = ref(1);
v-model="form.supply"
rows="3"
type="textarea"
maxlength="100"
maxlength="200"
placeholder="請填寫能分享的資源"
show-word-limit
/>
@ -367,7 +367,7 @@ const activeCollapse = ref(1);
v-model="form.demand"
rows="3"
type="textarea"
maxlength="100"
maxlength="200"
placeholder="請填寫能分享的資源"
show-word-limit
/>
@ -385,7 +385,7 @@ const activeCollapse = ref(1);
v-model="form.exchange"
rows="3"
type="textarea"
maxlength="100"
maxlength="200"
placeholder="請填寫能分享的資源"
show-word-limit
/>
@ -405,6 +405,7 @@ const activeCollapse = ref(1);
</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">

@ -11,11 +11,11 @@ import { useUserStore } from '@/store/user'
import { useRouter } from 'vue-router'
import { showToast, showFailToast, showLoadingToast, showSuccessToast } from 'vant';
import { showToast, showFailToast, showLoadingToast, showSuccessToast, showConfirmDialog } from 'vant';
import { getUserInfo, updateUserInfo, updateCard, searchConnection, addUserFavi, setUserNfcTpl } from '@/api'
import { updateUserExtra, updateUserLink, updateUserAddon } from '@/api/user';
import { updateUserExtra, updateUserLink, getUserExtra, updateUserAddon } from '@/api/user';
import { getAreaList, getWorkList } from '@/api/system';
import imgTp1 from '@/assets/images/tp/tp_1.jpg'
@ -32,8 +32,6 @@ const router = useRouter()
const form = ref({ addon: [] })
const uInfoForm = ref({ addon: [] })
const genderChecked = ref()
const resourceActive = ref('1');
@ -46,11 +44,33 @@ const tabActive = ref(0)
const tabItemObj = ref([
{ title: "基本資料", icon: "fa-id-card-clip" },
{ title: "社群分享", icon: "fa-share-nodes" },
{ title: "人脈資訊", icon: "fa-gem" },
{ title: "版型設定", icon: "fa-layer-group" }
{ title: "更多連結", icon: "fa-share-nodes" },
{ title: "菁英資訊", icon: "fa-gem" },
{ title: "NFC版型", icon: "fa-layer-group" }
]);
const beforeChange = (index) => {
return new Promise((resolve) => {
if (index === 1) {
if (form.value.level === 0 && form.value.status !== 2) {
showConfirmDialog({
title: '會員資格開通提醒',
message: '本功能為標準型以上之付費功能,是否前往立即開通?',
confirmButtonText: "立即開通"
}).then(() => {
router.push('/shop');
}).catch(() => {
// on cancel
});
}else{
resolve(true);
}
}else{
resolve(true);
}
});
};
const validatorUrl = (val) => {
if (val.length > 0) {
return /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/.test(val)
@ -79,8 +99,6 @@ onMounted(async () => {
let userRes = await getUserInfo()
if (userRes.code === 200) {
form.value = userRes.data
} else {
}
//
@ -89,7 +107,10 @@ onMounted(async () => {
areaColumns.value = areaRes.data
//
if (areaRes.data.length > 0) {
areaName.value = _.find(areaRes.data, { value: form.value.area }).text
const findRes = _.find(areaRes.data, { value: form.value.area })
if (findRes) {
areaName.value = findRes.text
}
}
}
@ -99,12 +120,16 @@ onMounted(async () => {
workColumns.value = workRes.data
//
if (workRes.data.length > 0) {
workName.value = _.find(workRes.data, { value: form.value.work }).text
const findRes = _.find(workRes.data, { value: form.value.work })
if (findRes) {
workName.value = findRes.text
}
}
}
if (userRes.data.nfc_addon && (userRes.data.nfc_addon.length > 0)) {
form.value.addon = JSON.parse(userRes.data.nfc_addon)
form.value.nfc_addon = JSON.parse(userRes.data.nfc_addon)
}
})
@ -158,62 +183,57 @@ const afterRead = async (file, name) => {
};
const onAddBtn = () => {
if (form.value.addon) {
form.value.addon.push({ icon: '', name: '', link: '' })
if (form.value.nfc_addon) {
form.value.nfc_addon.push({ icon: '', name: '', link: '' })
} else {
form.value.addon = [{ icon: '', name: '', link: '' }]
form.value.nfc_addon = [{ icon: '', name: '', link: '' }]
}
}
const onDelBtn = (index) => {
form.value.addon.splice(index, 1)
form.value.nfc_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]]
[form.value.nfc_addon[index], form.value.nfc_addon[index - 1]] = [form.value.nfc_addon[index - 1], form.value.nfc_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]]
if (index + 1 !== form.value.nfc_addon.length) {
[form.value.nfc_addon[index + 1], form.value.nfc_addon[index]] = [form.value.nfc_addon[index], form.value.nfc_addon[index + 1]]
}
}
}
const onSubmit = async () => {
showLoadingToast({
duration: 0,
message: '資料更新中...',
forbidClick: true,
});
// console.log(form.value,"test");
let res = await updateCard(form.value)
if (res.code === 200) {
showSuccessToast('更新成功')
router.push('/member')
} else {
showToast.fail('更新失敗')
const onFailed = (errorInfo) => {
console.log('failed', errorInfo);
showFailToast('請確認欄位填寫是否完整');
if(errorInfo.errors[0].name === 'url'){
tabActive.value = 1
return
}
tabActive.value = 0
return
};
const userInfoSubmit = async (values) => {
const onSubmit = async () => {
showLoadingToast({
duration: 0,
message: '資料更新中...',
forbidClick: true,
});
values.area = form.value.area
values.work = form.value.work
let res = await updateUserInfo(values)
// let res = await getUserInfo(form.value)
let res = await updateUserInfo(form.value)
if (res.code === 200) {
await userStore.getUserData();
showSuccessToast('更新成功')
userStore.getUserData();
router.push('/member')
} else {
showToast.fail('更新失敗')
showFailToast('更新失敗')
}
};
@ -221,28 +241,13 @@ const searchChecked = ref(true);
const searchOnUpdateValue = (newValue) => {
showConfirmDialog({
title: '提醒',
message: '是否切换开关',
message: '是否切换開關',
}).then(() => {
searchChecked.value = newValue;
});
};
const userExtraSubmit = async (values) => {
// showLoadingToast({
// duration: 0,
// message: '...',
// forbidClick: true,
// });
let res = await updateUserExtra(values)
if (res.code === 200) {
showSuccessToast('更新成功')
// router.push('/member')
} else {
showFailToast('更新失敗')
}
};
//
const showAreaPicker = ref(false);
const areaColumns = ref([]);
@ -262,44 +267,11 @@ const workName = ref('');
const onWorkConfirm = (value) => {
workName.value = value.selectedOptions[0].text
form.value.work = value.selectedOptions[0].value
showAreaPicker.value = false
showWorkPicker.value = false
}
// END:
// START:
const userLinkSubmit = async (values) => {
// showLoadingToast({
// duration: 0,
// message: '...',
// forbidClick: true,
// });
let res = await updateUserLink(values)
if (res.code === 200) {
showSuccessToast('更新成功')
// router.push('/member')
} else {
showFailToast('更新失敗')
}
};
const userAddonSubmit = async (values) => {
// showLoadingToast({
// duration: 0,
// message: '...',
// forbidClick: true,
// });
console.log(form.value.addon)
let res = await updateUserAddon(form.value.addon)
if (res.code === 200) {
showSuccessToast('更新成功')
} else {
showFailToast('更新失敗')
}
};
// END:
@ -310,14 +282,14 @@ const search = ref({
keyword: '',
})
const tab2result = ref('所需要的資源');
const tab2result = ref('菁英所需要的資源');
const tab2showPicker = ref(false);
const loading = ref(false);
const finished = ref(false);
const tab2columns = [
{ text: '所需要的資源', value: 0 },
{ text: '能提供的資源', value: 1 },
{ text: '菁英所需要的資源', value: 0 },
{ text: '菁英能提供的資源', value: 1 },
];
const tab2OnConfirm = ({ selectedOptions }) => {
@ -332,12 +304,23 @@ const tab2OnSearch = async () => {
};
const handleSearch = async () => {
showLoadingToast({
message: '人脈搜尋中...',
forbidClick: true,
});
let res = await searchConnection(search.value);
if (res.code === 200) {
tab2list.value = res.data;
console.log(tab2list.value)
}
};
//
const openNfcCard = (item) => {
window.open(`${item.nfcurl}`, '_blank');
};
const tab2list = ref([]);
const tab2Loading = ref(false);
@ -413,7 +396,7 @@ const handleSelectTpl = (id) => {
form.value.nfc_template = id
}
const handleChangeTplSubmit = async() => {
const handleChangeTplSubmit = async () => {
let res = await setUserNfcTpl(form.value.nfc_template);
if (res.code === 200) {
showSuccessToast('修改成功')
@ -435,7 +418,7 @@ const handleChangeTplSubmit = async() => {
</template>
</van-nav-bar>
<van-tabs class="van-tabs" :lazy-render="true" v-model:active="tabActive">
<van-tabs class="van-tabs" :lazy-render="true" v-model:active="tabActive" :ellipsis="false" :before-change="beforeChange">
<van-tab v-for="(item, index) in tabItemObj" :key="index">
<template #title>
<div class="tab_item">
@ -445,10 +428,9 @@ const handleChangeTplSubmit = async() => {
</template>
</van-tab>
</van-tabs>
<div class="content cnt0" v-show="tabActive === 0">
<van-cell-group inset>
<van-form @submit="userInfoSubmit">
<van-form @submit="onSubmit" @failed="onFailed">
<div class="content cnt0" v-show="tabActive === 0">
<van-cell-group inset>
<div class="text-center p-4">
<van-uploader :after-read="afterRead" :max-count="1" name="avatar" class="mb-4">
<div class="upload-main">
@ -479,9 +461,9 @@ const handleChangeTplSubmit = async() => {
<van-field v-model="form.age" label="年齡" name="age" placeholder="請輸入您的年齡" />
<van-field name="sex" label="性別">
<template #input>
<van-radio-group v-model="genderChecked" direction="horizontal" checked-color="#345068">
<van-radio name="0"></van-radio>
<van-radio name="1"></van-radio>
<van-radio-group v-model="form.sex" direction="horizontal" checked-color="#5b7b94">
<van-radio :name="1"></van-radio>
<van-radio :name="0"></van-radio>
</van-radio-group>
</template>
</van-field>
@ -489,39 +471,32 @@ const handleChangeTplSubmit = async() => {
<van-field v-model="areaName" is-link readonly name="area" label="區域" placeholder="請選擇區域"
@click="showAreaPicker = true" />
<van-popup v-model:show="showAreaPicker" position="bottom">
<van-picker :columns="areaColumns" @confirm="onAreaConfirm" @cancel="showAreaPicker = false" />
<van-picker :columns="areaColumns" confirm-button-text="" cancel-button-text="" @confirm="onAreaConfirm"
@cancel="showAreaPicker = false" />
</van-popup>
<van-field v-model="workName" is-link readonly name="work" label="工作性質" placeholder="請選擇工作性質"
@click="showWorkPicker = true" />
<van-popup v-model:show="showWorkPicker" position="bottom">
<van-picker :columns="workColumns" @confirm="onWorkConfirm" @cancel="showWorkPicker = false" />
<van-picker :columns="workColumns" confirm-button-text="" cancel-button-text="" @confirm="onWorkConfirm"
@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" />
active-color="#5b7b94" inactive-color="#888888" />
</template>
</van-field>
</van-cell-group>
<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 v-if="userStore.userData.level === 3">
<van-form @submit="userExtraSubmit">
<van-cell-group inset>
<van-cell class="text-center bg-lightPink py-3">
<template #title>
<h6 class="text-darkBlue"><strong>人脈資訊</strong></h6>
<h6 class="text-darkBlue"><strong>多元菁英人脈資訊</strong></h6>
<div style="text-align: center;">
下面為客製型會員專屬提供被搜尋
下面為<span class="text-danger">客製型會員</span>專屬提供被搜尋
</div>
</template>
</van-cell>
@ -538,68 +513,58 @@ const handleChangeTplSubmit = async() => {
padding: '0 16px',
}"><strong>貴人資源共享</strong></van-divider>
<van-collapse v-model="resourceActive" accordion>
<van-collapse-item title="工商簡介" name="3">
<van-field v-model="form.exchange" rows="3" type="textarea" name="exchange" maxlength="100"
<van-collapse-item title="工商簡介" name="1">
<van-field v-model="form.exchange" rows="5" type="textarea" name="exchange" maxlength="250"
placeholder="請填寫工商簡介" show-word-limit />
<van-field v-model="form.exchange_link" label="分享網址:" name="exchange_link" placeholder="需求連結" />
</van-collapse-item>
<van-collapse-item title="我能分享的資源" name="1">
<van-field v-model="form.supply" rows="3" type="textarea" maxlength="100" name="supply"
<van-collapse-item title="我能分享的資源" name="2">
<van-field v-model="form.supply" rows="5" type="textarea" maxlength="250" name="supply"
placeholder="請填寫能分享的資源" show-word-limit />
<van-field v-model="form.supply_link" label="分享網址:" name="supply_link" placeholder="分享網址"
:rules="[{ validator: validatorUrl, message: '網址格式不正確,Ex. http://' }]" />
</van-collapse-item>
<van-collapse-item title="我需要的資源" name="2">
<van-field v-model="form.demand" rows="3" type="textarea" maxlength="100" name="demand"
<van-collapse-item title="我需要的資源" name="3">
<van-field v-model="form.demand" rows="5" type="textarea" maxlength="250" name="demand"
placeholder="請填寫需要的的資源" show-word-limit />
<van-field v-model="form.demand_link" label="分享網址:" name="demand_link" placeholder="需求連結" />
</van-collapse-item>
</van-collapse>
</van-cell-group>
<div class="p-5">
<van-button block class="btn-darkBlue" native-type="submit">
確認修改
</van-button>
<van-sticky position="bottom">
<div class="bottomBtnCnt">
<van-button block class="btn-darkBlue" native-type="submit">確認修改</van-button>
</div>
</van-form>
</van-cell-group>
</div>
</van-sticky>
</div>
<div class="content cnt1" v-show="tabActive === 1">
<van-cell-group inset>
<van-form @submit="userLinkSubmit">
<van-field v-model="form.url" label="個人網頁" name="url" placeholder="請輸入您的個人網頁" />
<div class="content cnt1" v-show="tabActive === 1">
<van-cell-group inset>
<van-field v-model="form.url" label="個人網頁" name="url" placeholder="請輸入您的個人網頁"
:rules="[{ validator: validatorUrl, message: '網址格式不正確,Ex. https://' }]"/>
<van-field v-model="form.line" label="Line" name="line" placeholder="請輸入您的Line ID" />
<van-field v-model="form.facebook" label="Facebook" name="facebook" placeholder="請輸入您的Facebook" />
<van-field v-model="form.ig" label="IG" name="ig" placeholder="請輸入您的IG" />
<van-field v-model="form.youtube" label="YouTube" name="youtube" placeholder="請輸入您的YouTube" />
<van-field v-model="form.wechat" label="WeChat" name="wechat" placeholder="請輸入您的WeChat" />
<van-field v-model="form.tiktok" label="Tiktok" name="tiktok" placeholder="請輸入您的Tiktok" />
</van-cell-group>
<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="userAddonSubmit">
<van-cell-group inset>
<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">
<van-button size="small" @click="onAddBtn">
<h6>新增連結</h6>
</van-button>
</template>
</van-cell>
<van-field v-for="(item, idx) in form.addon" :key="idx">
<van-field v-for="(item, idx) in form.nfc_addon" :key="idx">
<template #label>
<van-field v-model="item.name" name="" maxlength="10" placeholder="請輸入您的連結名稱"
<van-field v-model="item.name" name="" maxlength="15" placeholder="請輸入名稱"
:rules="[{ required: true, message: '連結名稱必填' }]" />
</template>
<template #input>
@ -610,55 +575,42 @@ const handleChangeTplSubmit = async() => {
<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
:disabled="idx === 0"
@click="onMoveBtn(0, idx)"></van-button>
<van-button size="small" class="ml-1 btn-skyBlue" icon="arrow-down" plain hairline
:disabled="idx === form.nfc_addon.length - 1"
@click="onMoveBtn(1, idx)"></van-button>
</template>
</van-field>
</van-cell-group>
<!-- <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>
<van-sticky position="bottom">
<div class="bottomBtnCnt">
<van-button block class="btn-darkBlue" native-type="submit">確認修改</van-button>
</div>
</van-form>
</van-cell-group>
</div>
</van-sticky>
</div>
</van-form>
<div class="content cnt2" v-show="tabActive === 2">
<van-cell-group inset>
<van-row align="center">
<van-col span="12">
<van-row gutter="0" align="center">
<van-col span="9">
<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-picker confirm-button-text="" cancel-button-text="" :columns="tab2columns" @confirm="tab2OnConfirm"
@cancel="tab2showPicker = false" />
</van-popup>
</van-col>
<van-col span="12">
<van-search v-model="search.keyword" placeholder="請輸入搜尋關鍵字" @search="tab2OnSearch" />
<van-col span="15">
<van-search v-model="search.keyword" show-action placeholder="請輸入搜尋關鍵字" @search="tab2OnSearch">
<template #action>
<van-button class="btn-darkBlue" @click="tab2OnSearch">
搜索
</van-button>
</template>
</van-search>
</van-col>
</van-row>
</van-cell-group>
@ -684,7 +636,7 @@ const handleChangeTplSubmit = async() => {
</van-cell> -->
<div class="list-item" v-for="(item, index) in tab2list" :key="index">
<div class="left">
<div class="left" @click="openNfcCard(item)">
<div class="avatar"><img :src="item.avatar"></div>
<div class="text">
<h5 class="name ellipsis">{{ item.real_name }}</h5>
@ -717,62 +669,61 @@ const handleChangeTplSubmit = async() => {
</van-list>
</van-cell-group>
</div>
<div class="content cnt3" v-show="tabActive === 3">
<van-cell-group inset>
<van-form>
<van-form>
<van-cell-group inset>
<div class="block">
<van-image width="100%" position="top" fit="cover" :src="selectedTpl" />
</div>
</van-cell-group>
<van-cell-group inset>
<van-cell class="text-center bg-lightPink py-3">
<template #title>
<h6 class="text-darkBlue"><strong>感應式版型切換</strong></h6>
<h6 class="text-darkBlue"><strong>NFC感應式版型切換</strong></h6>
</template>
</van-cell>
<div class="block">
<van-image width="100%" position="top" fit="cover" :src="selectedTpl" />
</div>
<van-row>
<van-col span="12" v-for="(item, index) in tab3list" :key="index">
<div class="imgBtn" :data-id="index" @click="handleSelectTpl(item.id)">
<div class="imgCnt">
<van-image :src="item.image" />
</div>
</div>
</van-col>
</van-row>
</van-cell-group>
<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" @click="handleChangeTplSubmit">
確認修改
</van-button>
<van-sticky position="bottom">
<div class="bottomBtnCnt">
<van-button block class="btn-darkBlue" @click="handleChangeTplSubmit"></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" :data-id="index" @click="handleSelectTpl(item.id)">
<div class="imgCnt">
<van-image :src="item.image" />
</div>
</div>
</van-col>
</van-row>
</van-cell-group>
</van-sticky>
</van-form>
</div>
<!-- <Footer/> -->
<van-popup class="cropPopup" v-model:show="crop.show" closeable>
<h5 class="text-center mt-3">檔案裁切上傳</h5>
<div class="cropper-section">
<van-overlay :show="crop.show" @click="crop.show = false" />
<div class="cropper-section" v-if="crop.show">
<h5 class="text-center">檔案裁切上傳</h5>
<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 class="crop-btn">
<van-button round class="btn-darkBlue rounded-pill w-50" size="small" @click="() => { crop.show = false }">
取消
</van-button>
<van-button round class="btn-tomatoRed rounded-pill w-50" size="small" @click="onCrop">
裁切確認
</van-button>
</div>
</div>
</van-popup>
</div>
</template>
@ -780,96 +731,134 @@ const handleChangeTplSubmit = async() => {
<style src="@/assets/css/main.css"></style>
<style lang="less" scoped>
.cnt2 {
.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%;
.member {
.content {
min-height: calc(100vh - 142px);
padding-bottom: 0;
}
.cnt2 {
.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;
}
}
.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;
}
}
.name {
font-weight: bold;
.right {
flex: 0 0 auto;
}
}
.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;
.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;
}
}
}
}
}
}
.cnt3 {
.block {
height: 500px;
text-align: center;
background-color: #000;
padding: 20px 35px;
overflow: hidden;
overflow-y: auto;
.van-search,
.van-search-content {
padding-left: 0;
}
}
.imgBtn {
padding: 10px;
margin: 10px;
background-color: #333;
border-radius: 10px;
overflow: hidden;
cursor: pointer;
transform: scale(1);
transition: all .3s;
&.active,
&:hover {
transform: scale(1.02);
.cnt3 {
.block {
height: 50vh;
text-align: center;
background-color: #000;
padding: 20px 35px;
overflow: hidden;
overflow-y: auto;
}
.imgCnt {
width: 100%;
height: 150px;
.imgBtn {
padding: 10px;
margin: 10px;
background-color: #333;
border-radius: 10px;
overflow: hidden;
cursor: pointer;
transform: scale(1);
transition: all .3s;
&.active,
&:hover {
transform: scale(1.02);
}
img {
.imgCnt {
width: 100%;
height: 100%;
object-fit: cover;
height: 150px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
}
}</style>
}
.cropper-section {
margin: 0 auto;
position: fixed;
text-align: center;
top: 50px;
height: 350px;
width: 100%;
max-width: 500px;
background: hsl(0, 0%, 87%);
z-index: 8888;
.crop-area {
margin: 5 auto;
width: 100%;
// height: 330px;
}
.crop-btn {
text-align: center;
display: flex;
justify-content: space-between;
}
}
</style>

@ -7,8 +7,7 @@ import store from "@/store";
import router from "@/router";
import { useRoute } from "vue-router";
import { showToast } from "vant";
import { showLoadingToast,showSuccessToast } from 'vant';
import { showToast, showLoadingToast,showSuccessToast } from 'vant';
import { Cropper } from "vue-advanced-cropper";
import "vue-advanced-cropper/dist/style.css";
@ -21,7 +20,8 @@ const route = useRoute();
const form = ref({
verify: route.query.verify || null,
aid: route.query.aid || undefined,
user_id: route.query.user_id || null,
aid: route.query.aid || null,
});
const title = ref("註冊成為會員");
@ -33,7 +33,7 @@ const crop = ref({
img: null,
});
if (route.query.verify) {
if (route.query.verify || route.query.user_id) {
title.value = "會員開通";
}
@ -119,20 +119,21 @@ const onSubmit = async () => {
const id_token = liff.getIDToken();
showLoadingToast({
duration: 0,
message: "資料傳送中...",
forbidClick: true,
});
// 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,
refer: sessionStorage.getItem("refer") || null,
...form.value,
});
console.log(regRes.code,"regRes.code")
if (regRes.code === 500) {
if (liff.isLoggedIn()) {
liff.logout();
@ -143,7 +144,10 @@ const onSubmit = async () => {
showToast("註冊成功");
sessionStorage.setItem("token", regRes.data.token);
sessionStorage.setItem("uid", regRes.data.uid);
return router.push("/");
let redirect = sessionStorage.getItem("redirect") || "/";
sessionStorage.removeItem("redirect");
sessionStorage.removeItem("refer");
return router.push(redirect);
} else {
showToast("註冊失敗");
return;

@ -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,40 +1,61 @@
<script setup>
import liff from "@line/liff";
import { showToast,showSuccessToast } from 'vant';
import { showToast, showSuccessToast } from 'vant';
import { onMounted, reactive, ref, toRefs, computed, watch } from 'vue'
import { onMounted, ref, computed, watch } from 'vue'
import { getCard, getCusCard, getVipCard, updateSendCount } from '@/api'
import { getCard, getCusCard, getVipCard, updateSendCount, getFlexcard } from '@/api'
import { updateRemark, updateIsSend } from '@/api/card.js'
import { cardFactory } from '@/utils/card'
import { genCard1 } from '@/utils/card2'
import { genVipCard } from '@/utils/vipcard'
import { useStore } from 'vuex'
import { genAdCard } from '@/utils/adcard'
import { useUserStore } from '@/store/user';
import { useCardStore } from '@/store/card';
const userStore = useUserStore();
const cardStore = useCardStore();
const store = useStore()
const imageUrl = ref(import.meta.env.VITE_APP_BASE_URL)
const state = ref({
// active: 0,
showCusCard: false,
card_title: computed(() => store.state.user.userInfo.card_title),
card_title: computed(() => cusCardInfo.value.card_title),
vip_card: [],
flexContent: {},
})
const activeName = ref('0');
const activeName = ref('0')
const is_send = ref(0)
const remark = ref('')
let flexRef = ref(null)
const userInfo = computed(() => {
return store.state.user.userInfo
})
return userStore.userData;
});
const cusCardInfo = computed(() => {
return cardStore.cusCard;
});
// const vipCardInfo = computed(() => {
// return cardStore.vipCard;
// });
onMounted(async () => {
// console.log('liff',liff)
await liff.init({ liffId: import.meta.env.VITE_APP_LINE_LIFF_ID });
await userStore.getUserData();
await cardStore.getCardData();
if (userInfo.value.level > 2) {
let vipCardRes = await getVipCard({ userid: sessionStorage.getItem('uid') })
state.value.vip_card = vipCardRes.data
@ -43,34 +64,56 @@ onMounted(async () => {
}
})
//tab
watch(() => activeName.value, function (newVal, oldVal) {
if (newVal !== oldVal) {
showFlex(newVal)
if(parseInt(newVal) < 2){
is_send.value = 0
remark.value = ''
}
}
}, { immediate: true })
//
watch(() => userInfo.value.cus_card, function (newVal, oldVal) {
if (userInfo.value.level > 1 && newVal.length > 0) {
// if (userInfo.value.level > 1 && newVal > 0) {
if (userInfo.value.level > 1) {
state.value.showCusCard = true
}
}, { immediate: true })
//NFC
watch(() => userInfo.value.nc_template, function (newVal, oldVal) {
console.log('new', newVal)
showFlex('0')
})
async function showFlex(id) {
switch (id) {
case '0':
let { data: res } = await getCard({ userid: sessionStorage.getItem('uid') })
let { card } = cardFactory({ tid: userInfo.value.nc_template, vcard: res })
// let { card } = genCard(res)
state.value.flexContent = JSON.parse(card)
if (userInfo.value.status !== 0 && !userInfo.value.is_send_ad) { // &
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 = ''
flex2html("flex", state.value.flexContent)
break
case '1':
if (userInfo.value.level > 1) {
@ -89,6 +132,8 @@ async function showFlex(id) {
default:
if (userInfo.value.level > 2) {
// let vipCardRes = await getCusCard({userid: sessionStorage.getItem('uid')})
let vipCardRes = await getVipCard({ userid: sessionStorage.getItem('uid') })
state.value.vip_card = vipCardRes.data
let res = state.value.vip_card.find(item => { return item.id == id })
if (res.type === 0) {
state.value.flexContent = genCard1(JSON.parse(res.content))
@ -99,6 +144,9 @@ async function showFlex(id) {
flexRef.value.innerHTML = ''
flex2html("flex", state.value.flexContent)
}
is_send.value = res.is_send
remark.value = res.remark
// if( card2Res.code === 200){
// if(card2Res.data.cus_card){
// state.flexContent = genCard1(JSON.parse(card2Res.data.cus_card))
@ -113,26 +161,47 @@ async function showFlex(id) {
}
}
const handleOnChange = async () => {
//
let res = await updateIsSend({is_send:is_send.value,id:activeName.value})
if(res.code !== 200){
showToast('更新失敗')
}
}
const handleOnBlur = async () => {
//
let res = await updateRemark({remark:remark.value,id:activeName.value})
if(res.code !== 200){
showToast('更新失敗')
}
}
const sendEcard = async () => {
if (!liff.isLoggedIn()) {
liff.login({ redirectUri: window.location.href })
}
let content = JSON.parse(JSON.stringify(state.value.flexContent))
console.log(JSON.stringify(state.value.flexContent))
let res
if (activeName.value === '0') {
res = await liff.shareTargetPicker([content,
{
'type': 'text',
'text': '名片的連結都可以點擊!'
'text': '名片的文字、數字,都可連結,請多多指教!'
}])
} else {
res = await liff.shareTargetPicker([content])
if(is_send.value === 1){
res = await liff.shareTargetPicker([content,
{
'type': 'text',
'text': remark.value
}])
}else{
res = await liff.shareTargetPicker([content])
}
}
if (res.status === 'success') {
@ -168,8 +237,8 @@ function showChangeTpl() {
showDraw.value = true
}
const changeTpl = (val) => {
store.dispatch('user/setUserTpl', val)
const changeTpl = async (val) => {
userStore.setUserTpl(val)
showDraw.value = false
}
@ -177,19 +246,19 @@ const changeTpl = (val) => {
</script>
<template>
<div class="member page">
<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>
<h4><i class="fa-solid fa-angle-left text-white" :style="{ opacity: 0.5 }"></i></h4>
</template>
</van-nav-bar>
<div class="tab-section" v-cloak>
<van-tabs :lazy-render="true" v-model:active="activeName" v-show="userInfo.level > 1">
<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">
@ -203,7 +272,7 @@ const changeTpl = (val) => {
<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>
<p class="mb-3">{{ state.card_title }}</p>
</div>
</template>
</van-tab>
@ -212,7 +281,7 @@ const changeTpl = (val) => {
<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>
<p class="mb-3">{{ card.title }}</p>
</div>
</template>
</van-tab>
@ -220,11 +289,12 @@ const changeTpl = (val) => {
<!-- <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>
@ -232,14 +302,26 @@ const changeTpl = (val) => {
<h6 class="text-center text-white bg-darkBlue py-2">上面圖內分享無效請點下列分享</h6>
</div>
<div class="d-flex p-4">
<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 position="bottom">
<div v-if="parseInt(activeName) > 1" style="padding-top: 20px;">
<van-cell-group inset>
<van-cell center title="是否發送">
<template #right-icon>
<van-switch :active-value="1" :inactive-value="0" v-model="is_send" @change="handleOnChange"/>
</template>
</van-cell>
<van-field v-model="remark" label="分享內容附帶說明" label-width="120" nplaceholder="" @blur="handleOnBlur"/>
</van-cell-group>
</div>
<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>
@ -275,7 +357,7 @@ const changeTpl = (val) => {
.chatbox {
background-color: #333;
background-color: #222;
margin-top: 10px;
padding-top: 10px;
}
@ -289,8 +371,9 @@ const changeTpl = (val) => {
.tpl-list {
.tpl-item {
width:150px;
width: 150px;
padding: 10px;
img {
width: 100%;
}

@ -11,6 +11,13 @@ export default defineConfig(({ mode }) => {
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(),

Loading…
Cancel
Save