You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1039 lines
33 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<van-nav-bar
title="商務卡片"
right-text=""
@click-right="$router.push('/auth/getauth')"
/>
<keep-alive>
<div id="app" class="container my-4">
<div class="card-title">
<div>
會員編號{{$route.query.user_id}}
</div>
<div>
</div>
<div>
<van-button
icon="browsing-history"
type="primary"
@click="handlePreview"
>
預覽
</van-button>
</div>
</div>
<div class="card my-2">
<div class="card-header">
<ul class="card-header-tabs nav nav-tabs">
<li class="nav-item" @click="form.page = 'setting'">
<button
type="button"
class="nav-link"
:class="{ active: form.page === 'setting' }"
>
設定
</button>
</li>
<li
class="nav-item"
v-for="(card, index) in form.json5.cards"
:key="index"
@click="form.page = index + 1"
>
<button
type="button"
class="nav-link"
:class="{ active: form.page === index + 1 }"
>
{{ index + 1 }}
</button>
</li>
<li
class="nav-item"
@click="addCard"
v-if="form.json5.cards.length < 10"
>
<button type="button" class="nav-link">
<i class="fa fa-plus-circle"></i> +
</button>
</li>
</ul>
</div>
<!---->
<div class="card-content" v-if="form.page === 'setting'">
<div class="card-body">
<div class="form-group mb-2 was-validated">
<label for="utel-altText">標題文字</label>
<input
pattern=".+"
required="required"
id="utel-altText"
class="form-control form-control-sm"
v-model="form.title"
/>
<small class="form-text text-muted"
>與我的名片切換時顯示的文字。</small
>
</div>
<div class="form-group mb-2 was-validated">
<label for="utel-showNfc">是否顯示於感應名片</label>
<br />
<van-switch v-model="form.showNfc" />
<small class="form-text text-muted"
>與我的名片切換時顯示的文字。</small
>
</div>
</div>
</div>
<div class="card-content" v-else>
<div class="card-body pb-2 pt-3">
<div class="row">
<div class="col-sm-12" v-if="form.json5.cards.length > 1">
<div class="form-group mb-2 mb-2">
<label>控制卡片</label>
<div class="d-flex btn-group mb-1">
<button
type="button"
class="btn btn-sm btn-outline-info"
@click="moveCard(0, form.page)"
>
<i class="iconfont icon-arrow-o-l"></i> 前移
</button>
<button
type="button"
class="btn btn-sm btn-outline-info"
@click="moveCard(1, form.page)"
>
<i class="iconfont icon-arrow-o-r"></i> 後移
</button>
<button
type="button"
class="btn btn-sm btn-outline-danger"
@click="delCard(form.page)"
>
<i class="iconfont icon-delete"></i> 刪除
</button>
</div>
<small class="form-text text-muted"
>你可以點選前後移按鈕來移動卡片。</small
>
</div>
</div>
<div class="col-sm-12">
<div class="form-group mb-2 was-validated">
<label for="vcard-ratio">圖片長寬比</label>
<input
pattern=".+"
required="required"
id="vcard-ratio"
class="form-control form-control-sm"
v-model="form.json5.cards[form.page - 1].ratio"
/>
<small class="form-text text-muted">20:13 1:1 6:8。</small>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-image"> 卡片圖片 </label>
<div>
<van-uploader
:after-read="afterRead"
:max-count="1"
name="cardimage"
@delete="handleDelete"
>
<template
v-if="form.json5.cards[form.page - 1].image.length > 0"
>
<div class="upload-main">
<img
class="upload-img"
:src="form.json5.cards[form.page - 1].image"
alt=""
/>
</div>
</template>
<template v-else>
<div class="upload-main">
<img
class="upload-img"
src="@/assets/images/upload.jpg"
/>
<p>請上傳圖片</p>
</div>
</template>
</van-uploader>
</div>
<small class="form-text text-muted"></small>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-link">圖片網址連結</label>
<input
pattern="(https?://|line://|tel:|mailto:)\S+"
id="vcard-link"
inputmode="url"
type="url"
class="form-control form-control-sm"
v-model="form.json5.cards[form.page - 1].link"
/>
<small class="form-text text-muted">
連結(需輸入完整網址,http://..,https://...)
</small>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-titleColor">卡片底色</label>
<div class="input-group input-group-sm">
<input
pattern="#[0-9a-fA-F]{6}"
required="required"
id="vcard-bgColor"
inputmode="url"
class="form-control"
v-model="form.json5.cards[form.page - 1].bgColor"
/>
<div class="input-group-append">
<input
type="color"
class="form-control form-control-color"
v-model="form.json5.cards[form.page - 1].bgColor"
/>
&nbsp;色卡
</div>
</div>
<small class="form-text text-muted"
>請填寫卡片標題文字的顏色。</small
>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-title">卡片標題</label>
<input
pattern=".+"
required="required"
id="vcard-title"
class="form-control form-control-sm"
v-model="form.json5.cards[form.page - 1].title"
/>
<small class="form-text text-muted">請填寫卡片標題。</small>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-titleSize">標題文字大小(最大5xl最小xxs)</label>
<div class="input-group input-group-sm">
<input
pattern="[0-9a-zA-Z]+"
required="required"
id="vcard-titleSize"
class="form-control form-control-sm"
v-model="form.json5.cards[form.page - 1].titleSize"
/>
<div class="input-group-append">
<button
type="button"
data-toggle="dropdown"
class="btn btn-outline-secondary dropdown-toggle"
aria-expanded="false"
>
請選擇文字大小
</button>
<div class="dropdown-menu py-0" style="">
<button type="button" class="dropdown-item" @click="changeSize('titleSize',size)" v-for="(size,index) in sizeArr" :key="index">{{size}}</button>
</div>
</div>
</div>
<small class="form-text text-muted"
>請填寫卡片標題的文字大小。
</small>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-titleColor">標題文字顏色</label>
<div class="input-group input-group-sm">
<input
pattern="#[0-9a-fA-F]{6}"
required="required"
id="vcard-titleColor"
inputmode="url"
class="form-control"
v-model="form.json5.cards[form.page - 1].titleColor"
/>
<div class="input-group-append">
<input
type="color"
class="form-control form-control-color"
v-model="form.json5.cards[form.page - 1].titleColor"
/>
</div>
</div>
<small class="form-text text-muted"
>請填寫卡片標題文字的顏色。</small
>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-desc">卡片說明</label>
<textarea
id="vcard-desc"
pattern=".+"
required="required"
class="form-control form-control-sm"
v-model="form.json5.cards[form.page - 1].desc"
style="height: 100px"
></textarea>
<small class="form-text text-muted">請填寫卡片說明。</small>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-descSize">說明文字大小(最大5xl最小xxs)</label>
<div class="input-group input-group-sm">
<input
pattern="[0-9a-zA-Z]+"
required="required"
id="vcard-descSize"
class="form-control form-control-sm"
v-model="form.json5.cards[form.page - 1].descSize"
/>
<div class="input-group-append">
<button
type="button"
data-toggle="dropdown"
class="btn btn-outline-secondary dropdown-toggle"
aria-expanded="false"
>
請選擇文字大小
</button>
<div class="dropdown-menu py-0" style="">
<button type="button" class="dropdown-item" @click="changeSize('descSize',size)" v-for="(size,index) in sizeArr" :key="index">{{size}}</button>
</div>
</div>
</div>
<small class="form-text text-muted"
>請填寫卡片標題的文字大小
</small>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-titleColor">說明文字顏色</label>
<div class="input-group input-group-sm">
<input
pattern="#[0-9a-fA-F]{6}"
required="required"
id="vcard-titleColor"
inputmode="url"
class="form-control"
v-model="form.json5.cards[form.page - 1].descColor"
/>
<div class="input-group-append">
<input
type="color"
class="form-control form-control-color"
v-model="form.json5.cards[form.page - 1].descColor"
/>
</div>
</div>
<small class="form-text text-muted"
>請填寫卡片標題文字的顏色。</small
>
</div>
<!-- <div class="form-group mb-2 was-validated">
<label for="vcard-title">卡片連結</label>
<input
pattern=".+"
required="required"
id="vcard-title"
class="form-control form-control-sm"
v-model="form.json5.cards[form.page - 1].title"
/>
<small class="form-text text-muted">請填寫卡片標題。</small>
</div> -->
</div>
</div>
</div>
<ul class="list-group list-group-flush">
<li
class="list-group-item pb-2 pt-3"
v-for="(btn, index) in form.json5.cards[form.page - 1].btns"
:key="index"
>
<div class="row">
<div class="col-sm-12">
<div class="form-group mb-2">
<label>控制按鈕 {{ index + 1 }}</label>
<div class="d-flex btn-group mb-1">
<button
type="button"
class="btn btn-sm btn-outline-info"
@click="moveBtn(0, index)"
v-if="form.json5.cards[form.page - 1].btns.length > 1"
>
<i class="iconfont icon-arrow-o-u"></i> 上移
</button>
<button
type="button"
class="btn btn-sm btn-outline-info"
@click="moveBtn(1, index)"
v-if="form.json5.cards[form.page - 1].btns.length > 1"
>
<i class="iconfont icon-arrow-o-d"></i> 下移
</button>
<button
type="button"
class="btn btn-sm btn-outline-danger"
@click="delBtn(index)"
>
<i class="iconfont icon-delete"></i> 刪除
</button>
</div>
</div>
</div>
<div class="col-sm-12">
<div class="form-group mb-2 was-validated">
<label for="cardbtn-text-0"
>按鈕 {{ index + 1 }} 文字</label
>
<input
pattern=".+"
required="required"
id="cardbtn-text-0"
class="form-control form-control-sm"
v-model="btn.text"
/>
</div>
<div class="form-group mb-2 was-validated">
<label for="cardbtn-link-0"
>按鈕
{{
index + 1
}}
連結(需輸入完整網址,http://..,https://...)</label
>
<input
pattern="(https?://|line://|tel:|mailto:)\S+"
required="required"
inputmode="url"
type="url"
id="cardbtn-link-0"
class="form-control form-control-sm"
v-model="btn.link"
/>
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-titleColor">按鈕文字顏色</label>
<div class="input-group input-group-sm">
<input
pattern="#[0-9a-fA-F]{6}"
required="required"
id="vcard-titleColor"
inputmode="url"
class="form-control"
v-model="btn.color"
/>
<div class="input-group-append">
<input
type="color"
class="form-control form-control-color"
v-model="btn.color"
/>
</div>
</div>
<!-- <small class="form-text text-muted">請填寫卡片標題文字的顏色。</small> -->
</div>
<div class="form-group mb-2 was-validated">
<label for="vcard-btnHeight">按鈕大小</label>
<div class="input-group input-group-sm">
<input
pattern="[0-9a-zA-Z]+"
required="required"
id="vcard-btnHeight"
class="form-control form-control-sm"
v-model="btn.btnHeight"
/>
<div class="input-group-append">
<button
type="button"
data-toggle="dropdown"
class="btn btn-outline-secondary dropdown-toggle"
aria-expanded="false"
>
請選擇按鈕大小
</button>
<div class="dropdown-menu py-0" style="">
<button type="button" class="dropdown-item" @click="btn.btnHeight='sm'" >sm</button>
<button type="button" class="dropdown-item" @click="btn.btnHeight='md'" >md</button>
</div>
</div>
</div>
<small class="form-text text-muted"
>請填寫卡片標題的文字大小。
</small>
</div>
</div>
</div>
</li>
<li class="list-group-item">
<button
type="button"
class="btn btn-outline-success"
@click="addBtn(form.page)"
>
<i class="fa fa-plus-circle"></i> 新增按鈕
</button>
<button
type="button"
class="btn btn-outline-success"
@click="addShareBtn(form.page)"
>
<i class="fa fa-plus-circle"></i> 新增分享按鈕
</button>
</li>
</ul>
</div>
</div>
<div class="d-flex mx-n2 my-2 row">
<div class="btn flex-fill mx-2 my-1 btn-primary" @click="handleSubmit">
<i class="fa mr-2 fa-id-card-o"></i> 建立名片
</div>
</div>
<div
id="modal-exportimport"
data-backdrop="static"
data-keyboard="false"
tabindex="-1"
class="fade modal"
>
<div
class="align-items-stretch modal-dialog modal-dialog-centered modal-xl"
>
<div class="modal-content">
<div class="d-flex flex-column modal-body">
<textarea
class="form-control form-control-sm flex-fill"
></textarea>
<small class="form-text text-muted"
>請複製匯出的資料,或貼上之前的資料並點一下「匯入」按鈕。</small
>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-success">
複製
</button>
<button type="button" class="btn btn-secondary">關閉</button>
<button type="button" class="btn btn-primary">匯入</button>
</div>
</div>
</div>
</div>
</div>
</keep-alive>
<Footer v-if="showFooter" />
<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: 20 / 13,
}"
: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>
</template>
<script>
import Footer from "@/components/Footer.vue";
import FlexView from "@/components/FlexView.vue";
import {
ref,
reactive,
toRefs,
watch,
onBeforeMount,
defineComponent,
onMounted,
} from "vue";
import { updateCusCard } from "@/api";
import { useStore } from "vuex";
import { useRouter ,useRoute} from "vue-router";
import axios from "axios";
import _ from "lodash";
import { showToast,showLoadingToast,showSuccessToast } from "vant";
import { Cropper } from "vue-advanced-cropper";
import "vue-advanced-cropper/dist/style.css";
import { genCard1 } from "@/utils/card2";
import { getCusCard } from "@/api";
const URL = window.URL || window.webkitURL;
export default defineComponent({
name: "EditCard",
components: {
Footer,
Cropper,
FlexView,
},
async setup() {
const store = useStore();
const route = useRoute();
const router = useRouter();
const myCrop = ref(null);
const showNfc = ref(false);
const showPreview = ref(false);
let flexRef = ref(null);
const crop = ref({
show: false,
img: null,
outputType: "jpeg",
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
});
let state = reactive({
imagePath: "",
previewImage: null,
fileList: [],
showFooter: true,
form: {
page: 1,
title: "商務卡片",
showNfc: true,
json5: {
altText: '',
btnHeight: "md",
descSize: "sm",
titleSize: "xl",
cards: [
{
bgColor: "#ffffff",
desc: "",
descColor: "#000000",
image: "",
link: "",
title: "",
titleSize: "xl",
descSize: "sm",
titleColor: "#000000",
ratio: "20:13",
},
],
},
},
});
const sizeArr = ref(['xxs','xs','sm','md','lg','xl','xxl','3xl','4xl','5xl'])
let userid;
onMounted(async()=>{
userid = route.query.user_id;
let res = await getCusCard({ userid })
if(res.code===200){
if(res.data.cus_card && res.data.cus_card.length>0){
state.form = JSON.parse(res.data.cus_card)
}
}
})
watch(()=>state.form.title,(newVal)=>{
state.form.json5.altText = newVal
})
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("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}/card/uploadfile`,
imgFile,
{}
);
if (res.data.code == 200) {
state.form.json5.cards[state.form.page - 1].image = res.data.data;
showSuccessToast("上傳成功");
} else {
showToast.fail("上傳失敗");
}
}, "image/jpeg");
}
return;
};
const onClose = () => {
crop.value.show = false;
};
const addCard = () => {
state.form.json5.cards.push({
bgColor: "#ffffff",
desc: "",
descColor: "#000000",
image: "",
// link: "",
title: "",
titleSize: "xl",
descSize: "sm",
titleColor: "#000000",
ratio: "20:13",
});
state.form.page = state.form.json5.cards.length;
};
const delCard = (page) => {
if (page > 1) {
state.form.page = page - 1;
}
state.form.json5.cards.splice(page - 1, 1);
};
const addBtn = (page) => {
if (!state.form.json5.cards[page - 1].btns) {
state.form.json5.cards[page - 1].btns = [];
}
state.form.json5.cards[page - 1].btns.push({
color: "#42659a",
link: "",
style: "primary",
text: "",
btnHeight: "md"
});
};
const addShareBtn = (page) => {
if (!state.form.json5.cards[page - 1].btns) {
state.form.json5.cards[page - 1].btns = [];
}
state.form.json5.cards[page - 1].btns.push({
color: "#42659a",
link: `${import.meta.env.VITE_APP_SEND_URL}?userid=${userid}&cardid=2`,
style: "primary",
text: "分享好友",
btnHeight: "md"
});
};
const moveCard = (type, page) => {
if (type === 0) {
if (page !== 1) {
[state.form.json5.cards[page - 1], state.form.json5.cards[page - 2]] =
[
state.form.json5.cards[page - 2],
state.form.json5.cards[page - 1],
];
state.form.page = page - 1;
}
} else {
if (page !== state.form.json5.cards.length) {
[state.form.json5.cards[page], state.form.json5.cards[page - 1]] = [
state.form.json5.cards[page - 1],
state.form.json5.cards[page],
];
state.form.page = page + 1;
}
}
};
const delBtn = (index) => {
// console.log('index',state.json5.cards[state.page-1].btns)
state.form.json5.cards[state.form.page - 1].btns.splice(index, 1);
if (state.form.json5.cards[state.form.page - 1].btns.length === 0) {
delete state.form.json5.cards[state.form.page - 1].btns;
}
};
const moveBtn = (type, index) => {
if (type === 0) {
if (index !== 0) {
[
state.form.json5.cards[state.form.page - 1].btns[index],
state.form.json5.cards[state.form.page - 1].btns[index - 1],
] = [
state.form.json5.cards[state.form.page - 1].btns[index - 1],
state.form.json5.cards[state.form.page - 1].btns[index],
];
}
} else {
if (
index + 1 !==
state.form.json5.cards[state.form.page - 1].btns.length
) {
[
state.form.json5.cards[state.form.page - 1].btns[index + 1],
state.form.json5.cards[state.form.page - 1].btns[index],
] = [
state.form.json5.cards[state.form.page - 1].btns[index],
state.form.json5.cards[state.form.page - 1].btns[index + 1],
];
}
}
};
const afterRead = async (file, name) => {
// crop.value.show = true
// const ofile = file.file
// crop.value.img = URL.createObjectURL(ofile);
const imgFile = new FormData();
imgFile.append("fileType", "IMAGE");
imgFile.append("file", file.file);
showLoadingToast({
duration: 0,
message: "圖片上傳中...",
forbidClick: true,
});
let res = await axios.post(
`${import.meta.env.VITE_APP_API_URL}/card/uploadfile`,
imgFile,
{}
);
if (res.data.code == 200) {
state.form.json5.cards[state.form.page - 1].image = res.data.data;
showSuccessToast("上傳成功");
} else {
showToast.fail("上傳失敗");
}
return;
};
const handleDelete = () => {
state.form.json5.cards[state.form.page - 1].image = "";
};
const handlePreview = () => {
router.push({
name: "AuthPreview",
params: { content: JSON.stringify(state.form) },
});
};
const changeSize = (type,size)=>{
switch(type){
case 'titleSize':
state.form.json5.cards[state.form.page - 1].titleSize = size;
break;
case 'descSize':
state.form.json5.cards[state.form.page - 1].descSize = size;
break;
default:
break;
}
return
}
const handleSubmit = async () => {
if (!validateForm(state.form.json5.cards)) {
showToast("商務卡片欄位錯誤,紅色錯誤欄位請重新檢查!!");
return;
}
let user_id = userid;
showLoadingToast({
duration: 0,
message: "名片上傳中...",
forbidClick: true,
});
let res = await updateCusCard({
user_id: user_id,
card_title: state.form.title,
show_cus: state.form.showNfc,
cus_card: JSON.stringify(state.form),
});
if (res.code === 200) {
store.commit("user/setCusCard", JSON.stringify(state.form));
showSuccessToast("建立成功");
} else {
showToast.fail("建立失敗");
}
router.push("/auth/getauth");
};
//檢查表單是否為空
function validateForm(data) {
let pattern = /(https?:\/\/|line:\/\/|tel:|mailto:)\S+/;
for (let [index, val] of data.entries()) {
// let rtn = Object.values(val).some((v) => {
// return v == "" || v == null;
// });
let rtn = false
for(let i in val){
if(i !=='link' && (val[i] == "" || val[i] == null)){
rtn = true
}
}
if (rtn === true) {
state.form.page = index + 1;
return false;
}
// if(!pattern.test(val.link)){
// state.form.page = index+1
// return false
// }
if(val.link){
val.link = val.link.trim()
}
if (val.btns && val.btns.length > 0) {
for (let btn of val.btns) {
let rtn = Object.values(btn).some((v) => {
return v == "" || v == null;
});
if (rtn === true) {
state.form.page = index + 1;
return false;
}
btn.link = btn.link.trim()
if (!pattern.test(btn.link)) {
state.form.page = index + 1;
return false;
}
}
}
}
return true;
}
function validateBtn(data) {
return false;
}
return {
...toRefs(state),
sizeArr,
showPreview,
flexRef,
crop,
myCrop,
addCard,
delCard,
moveCard,
addBtn,
addShareBtn,
delBtn,
moveBtn,
afterRead,
handlePreview,
handleDelete,
changeSize,
handleSubmit,
onCrop,
onClose,
};
},
});
</script>
<style lang="less" scoped>
.form-control.form-control-color,
.was-validated .form-control.form-control-color:valid {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
background: 0 0;
border: 1px solid #ced4da;
height: auto;
padding: 0.375rem;
width: 3rem;
padding-right: 0.375rem !important;
}
.card-title {
display: flex;
justify-content: center;
align-items: center;
div:nth-child(1) {
flex: 1;
}
div:nth-child(2) {
width: 120px;
}
div:nth-child(3) {
width: 90px;
}
}
.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;
}
}
.flex-section {
width: 100%;
}
</style>