h888
Wayne Hsu 3 years ago
parent 99cb2b8828
commit 5e2036c6ad

3
components.d.ts vendored

@ -14,12 +14,15 @@ declare module '@vue/runtime-core' {
UserHeader: typeof import('./src/components/UserHeader.vue')['default']
VanButton: typeof import('vant/es')['Button']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanCollapse: typeof import('vant/es')['Collapse']
VanCollapseItem: typeof import('vant/es')['CollapseItem']
VanDatePicker: typeof import('vant/es')['DatePicker']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanGrid: typeof import('vant/es')['Grid']
VanGridItem: typeof import('vant/es')['GridItem']
VanIcon: typeof import('vant/es')['Icon']
VanNavBar: typeof import('vant/es')['NavBar']
VanOverlay: typeof import('vant/es')['Overlay']
VanPicker: typeof import('vant/es')['Picker']
VanPopover: typeof import('vant/es')['Popover']

@ -1,42 +1,42 @@
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="author" content="" />
<link rel="manifest" href="/manifest.json" />
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="/favicon.ico" />
<meta name="theme-color" content="#0baf9a" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="Fastkart" />
<meta name="msapplication-TileImage" content="/assets/images/favicon.png" />
<meta name="msapplication-TileColor" content="#FFFFFF" />
<head>
<meta charset="UTF-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="author" content="" />
<link rel="manifest" href="/manifest.json" />
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="/favicon.ico" />
<meta name="theme-color" content="#0baf9a" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="Fastkart" />
<meta name="msapplication-TileImage" content="/assets/images/favicon.png" />
<meta name="msapplication-TileColor" content="#FFFFFF" />
<!-- Bootstrap 5 -->
<link rel="stylesheet" id="rtl-link" type="text/css" href="/assets/css/vendors/bootstrap.css" />
<!-- Bootstrap 5 -->
<link rel="stylesheet" id="rtl-link" type="text/css" href="/assets/css/vendors/bootstrap.css" />
<!-- Iconly Icon css -->
<!-- <link rel="stylesheet" type="text/css" href="assets/css/iconly.css" /> -->
<link href="https://dev.iconly.io/public/zmWANpvJMPK2/iconly.css" rel="stylesheet"/>
<!-- Iconly Icon css -->
<!-- <link rel="stylesheet" type="text/css" href="assets/css/iconly.css" /> -->
<link href="https://dev.iconly.io/public/zmWANpvJMPK2/iconly.css" rel="stylesheet" />
<!-- Slick css -->
<!-- <link rel="stylesheet" type="text/css" href="assets/css/vendors/slick.css" />
<!-- Slick css -->
<!-- <link rel="stylesheet" type="text/css" href="assets/css/vendors/slick.css" />
<link rel="stylesheet" type="text/css" href="assets/css/vendors/slick-theme.css" /> -->
<!-- Style css -->
<!-- <link rel="stylesheet" id="change-link" type="text/css" href="assets/css/style.css" /> -->
<!-- Style css -->
<!-- <link rel="stylesheet" id="change-link" type="text/css" href="assets/css/style.css" /> -->
<title>UTel電商</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script src="https://js.tappaysdk.com/sdk/tpdirect/v5.15.0"></script>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
</body>
<title>Slash電商</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script src="https://js.tappaysdk.com/sdk/tpdirect/v5.15.0"></script>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
</body>
</html>

@ -1,240 +1,285 @@
<template>
<!-- Header Start -->
<header class="header">
<div class="logo-wrap">
<i class="icon-arrow-left-bold-box icli" @click="$router.go(-1)"></i>
<h1 class="title-color font-md">選擇收貨地址</h1>
</div>
</header>
<!-- Header End -->
<!-- Main Start -->
<main class="main-wrap address2-page mb-xxl">
<!-- Address Section Start -->
<section class="pt-0">
<button class="d-block btn-outline-grey" @click="showOffcanvas = true">+ 增加新地址</button>
<div class="address-wrap">
<!-- Address Star -->
<div class="address-box"
:class="{active: ua.is_default}"
v-for="(ua,index) in userAddr"
:key="ua.address_id"
@click="handleSetDefault(ua.address_id)">
<div class="conten-box">
<div class="heading">
<div class="heading-left">
<i class="icon-home icli"></i>
<h2 class="title-color font-md">{{ ua.address_name }}</h2>
<span class="badges-round font-white bg-theme-theme font-xs" v-if="ua.is_default"></span>
</div>
<div class="heading-right">
<i class="icon-trash" @click.stop="handleDelete(ua.address_id)"></i>
</div>
</div>
<h3 class="title-color font-sm">{{ ua.consignee }}</h3>
<h3 class="title-color font-sm">{{ ua.tel }}</h3>
<p class="content-color font-sm">{{ ua.address }}</p>
</div>
<!-- <img src="/src/assets/images/map/map.jpg" alt="map" /> -->
<!-- Header Start -->
<header class="header">
<div class="logo-wrap">
<i class="icon-arrow-left-bold-box icli" @click="$router.go(-1)"></i>
<h1 class="title-color font-md">選擇收貨地址</h1>
</div>
<!-- Address End -->
</div>
</section>
<!-- Address Section End -->
</main>
<!-- Main End -->
</header>
<!-- Header End -->
<!-- Main Start -->
<main class="main-wrap address2-page mb-xxl">
<!-- Address Section Start -->
<section class="pt-0">
<button class="d-block btn-outline-grey" @click="showOffcanvas = true">+ 增加新地址</button>
<div class="address-wrap">
<!-- Address Star -->
<div
class="address-box"
:class="{ active: ua.is_default }"
v-for="(ua, index) in userAddr"
:key="ua.address_id"
@click="handleSetDefault(ua.address_id)"
>
<div class="conten-box">
<div class="heading">
<div class="heading-left">
<i class="icon-home icli"></i>
<h2 class="title-color font-md">{{ ua.address_name }}</h2>
<span class="badges-round font-white bg-theme-theme font-xs" v-if="ua.is_default"
>預設</span
>
</div>
<div class="heading-right">
<i class="icon-trash" @click.stop="handleDelete(ua.address_id)"></i>
</div>
</div>
<h3 class="title-color font-sm">{{ ua.consignee }}</h3>
<h3 class="title-color font-sm">{{ ua.tel }}</h3>
<p class="content-color font-sm">{{ ua.address }}</p>
</div>
<!-- <img src="/src/assets/images/map/map.jpg" alt="map" /> -->
</div>
<!-- Address End -->
</div>
</section>
<!-- Address Section End -->
</main>
<!-- Main End -->
<!-- Footer Start -->
<!-- <footer class="footer-wrap footer-button">
<!-- Footer Start -->
<!-- <footer class="footer-wrap footer-button">
<a href="payment.html" class="font-md">Proceed to Payment</a>
</footer> -->
<!-- Footer End -->
<!-- Add New Address Off Canvas Start -->
<van-popup
v-model:show="showOffcanvas"
round
closeable
position="bottom"
>
<div class="offcanvas-header">
<h5 class="title-color font-md fw-600">增加住址</h5>
</div>
<van-form @submit="onSubmit" ref="addrForm">
<div class="offcanvas-body small">
<van-cell-group inset>
<van-field v-model="form.name" name="name" label="住址名稱" placeholder="自己可以識別的名稱"
:rules="[{ required: true, message: '請填寫住址名稱' }]" />
<van-field v-model="form.consignee" name="consignee" label="聯絡人" placeholder="聯絡人"
:rules="[{ required: true, message: '請填寫聯絡人姓名' }]" />
<van-field v-model="form.tel" name="tel" label="聯絡電話" placeholder="聯絡電話"
:rules="[{ required: true, message: '請填寫聯絡電話' }]" />
<van-field v-model="fieldValue" is-link readonly name="area" label="地區" placeholder="請選擇區域"
@click="showPicker = true" />
<van-popup v-model:show="showPicker" position="bottom">
<van-picker
name = "selectedValue"
v-model = "form.selectedValue"
:columns="columns"
@confirm="onConfirm"
@cancel="showPicker = false"
confirm-button-text = "確認"
cancel-button-text = "取消"
/>
</van-popup>
<van-field v-model="form.zipcode" name="zipcode" label="郵遞區號" placeholder="郵遞區號" />
<van-field v-model="form.address" name="address" label="詳細地址" placeholder="詳細地址"
:rules="[{ required: true, message: '請填寫詳細地址' }]" />
<van-field name="is_default" label="是否為預設">
<template #input>
<van-switch v-model="form.is_default" />
</template>
</van-field>
</van-cell-group>
</div>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
新增
</van-button>
</div>
</van-form>
</van-popup>
<!-- Add New Address Off Canvas End -->
<!-- Footer End -->
<!-- Add New Address Off Canvas Start -->
<van-popup v-model:show="showOffcanvas" round closeable position="bottom">
<div class="offcanvas-header">
<h5 class="title-color font-md fw-600">增加住址</h5>
</div>
<van-form @submit="onSubmit" ref="addrForm">
<div class="offcanvas-body small">
<van-cell-group inset>
<van-field
v-model="form.name"
name="name"
label="住址名稱"
placeholder="自己可以識別的名稱"
:rules="[{ required: true, message: '請填寫住址名稱' }]"
/>
<van-field
v-model="form.consignee"
name="consignee"
label="聯絡人"
placeholder="聯絡人"
:rules="[{ required: true, message: '請填寫聯絡人姓名' }]"
/>
<van-field
v-model="form.tel"
name="tel"
label="聯絡電話"
placeholder="聯絡電話"
:rules="[{ required: true, message: '請填寫聯絡電話' }]"
/>
<van-field
v-model="fieldValue"
is-link
readonly
name="area"
label="地區"
placeholder="請選擇區域"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker
name="selectedValue"
v-model="form.selectedValue"
:columns="columns"
@confirm="onConfirm"
@cancel="showPicker = false"
confirm-button-text="確認"
cancel-button-text="取消"
/>
</van-popup>
<van-field v-model="form.zipcode" name="zipcode" label="郵遞區號" placeholder="郵遞區號" />
<van-field
v-model="form.address"
name="address"
label="詳細地址"
placeholder="詳細地址"
:rules="[{ required: true, message: '請填寫詳細地址' }]"
/>
<van-field name="is_default" label="是否為預設">
<template #input>
<van-switch v-model="form.is_default" />
</template>
</van-field>
</van-cell-group>
</div>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit"> 新增 </van-button>
</div>
</van-form>
</van-popup>
<!-- Add New Address Off Canvas End -->
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { showToast } from 'vant'
import 'vant/es/toast/style'
import { ref, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useOrderStore } from "@/store/Order";
import { showToast } from "vant";
import "vant/es/toast/style";
import { getArea } from '@/services/shop'
import { getUserAddress,
addUserAddress,
delUserAddress,
setUserAddressDefault } from '@/services/user'
import { getArea } from "@/services/shop";
import { getUserAddress, addUserAddress, delUserAddress, setUserAddressDefault } from "@/services/user";
const showPicker = ref(false)
const route = useRoute();
const router = useRouter();
const orderStore = useOrderStore();
const showOffcanvas = ref(false)
const showPicker = ref(false);
const fieldValue = ref('')
const showOffcanvas = ref(false);
const userAddr = ref([])
const fieldValue = ref("");
const columns = ref([])
const userAddr = ref([]);
const addrForm = ref()
const columns = ref([]);
const addrForm = ref();
const form = ref({
name: '住家',
consignee:'',
tel:'',
area:'',
zipcode: '',
address:'',
selectedValue:['0'],
is_default: false
})
name: "住家",
consignee: "",
tel: "",
area: "",
zipcode: "",
address: "",
selectedValue: ["0"],
is_default: false,
});
onMounted(async () => {
let addrRes = await getUserAddress()
let addrRes = await getUserAddress();
if(addrRes.code === 200){
userAddr.value = addrRes.data
}
if (addrRes.code === 200) {
userAddr.value = addrRes.data;
}
let areaRes = await getArea()
if(areaRes.code === 200){
columns.value = areaRes.data
}
})
let areaRes = await getArea();
if (areaRes.code === 200) {
columns.value = areaRes.data;
}
});
const onConfirm = ({ selectedOptions }) => {
showPicker.value = false;
showPicker.value = false;
let selectedArea = selectedOptions[0].text
if(selectedOptions[1]){
selectedArea += '-' + selectedOptions[1].text
}
if(selectedOptions[2]){
selectedArea += '-' + selectedOptions[2].text
}
let selectedArea = selectedOptions[0].text;
if (selectedOptions[1]) {
selectedArea += "-" + selectedOptions[1].text;
}
if (selectedOptions[2]) {
selectedArea += "-" + selectedOptions[2].text;
}
fieldValue.value = selectedArea
}
fieldValue.value = selectedArea;
};
const handleSubmit = () => {
// addrForm.value.submit()
}
// addrForm.value.submit()
};
const handleClose = () => {
addrForm.value.resetValidation()
}
addrForm.value.resetValidation();
};
const onSubmit = async () => {
let res = await addUserAddress(form.value)
showOffcanvas.value = false
if(res.code === 200){
userAddr.value = res.data
return showToast('新增成功')
}else{
return showToast('新增失敗')
}
}
let res = await addUserAddress(form.value);
showOffcanvas.value = false;
if (res.code === 200) {
userAddr.value = res.data;
return showToast("新增成功");
} else {
return showToast("新增失敗");
}
};
const handleDelete = async (id) => {
let res = await delUserAddress(id)
if(res.code === 200){
userAddr.value = userAddr.value.filter((item)=>{
if(item.address_id !== id){
return item
}
})
showToast('刪除成功')
}else{
showToast('刪除失敗')
}
}
let res = await delUserAddress(id);
if (res.code === 200) {
userAddr.value = userAddr.value.filter((item) => {
if (item.address_id !== id) {
return item;
}
});
showToast("刪除成功");
} else {
showToast("刪除失敗");
}
};
const handleSetDefault = async (id) => {
let res = await setUserAddressDefault(id)
if(res.code === 200){
// userAddr.value = res.data
userAddr.value = userAddr.value.map((item)=>{
if(item.address_id === id){
item.is_default = true
}else{
item.is_default = false
}
return item
})
}
}
let res = await setUserAddressDefault(id);
if (res.code === 200) {
// userAddr.value = res.data
userAddr.value = userAddr.value.map((item) => {
if (item.address_id === id) {
item.is_default = true;
} else {
item.is_default = false;
}
return item;
});
//orderpianacheckout page
if (route.query.from === "order") {
let addr = userAddr.value.find((item) => {
if (item.address_id === id) {
return item;
}
});
orderStore.shipping = {
shipping_code: "shipping",
extra_data: {
address: addr.address,
consignee: addr.consignee,
tel: addr.tel,
},
};
router.replace("/checkout");
}
}
};
</script>
<style lang="less" scoped>
.conten-box{
width: 100%;
.conten-box {
width: 100%;
}
.heading{
display: flex;
justify-content: space-between;
.heading-left{
.heading {
display: flex;
h2{
margin: 0 10px;
justify-content: space-between;
.heading-left {
display: flex;
h2 {
margin: 0 10px;
}
}
}
.heading-right {
}
.heading-right {
}
}
</style>

@ -1,47 +1,41 @@
<template>
<!-- Main Start -->
<main class="main-wrap order-success-page mb-xxl">
<!-- Banner Section Start -->
<section class="banner-section">
<div class="banner-wrap">
<img src="@/assets/svg/order-success.svg" alt="order-success" />
</div>
<div class="content-wrap">
<h1 class="font-lg title-color">感謝您的購買</h1>
<p class="font-sm content-color">您的訂單已成功下達您的訂單編號為#{{ order_sn }}</p>
</div>
</section>
<!-- Banner Section End -->
<!-- Banner Section Start -->
<section class="banner-section">
<div class="banner-wrap">
<img src="@/assets/svg/order-success.svg" alt="order-success" />
</div>
<div class="content-wrap">
<h1 class="font-lg title-color">感謝您的購買</h1>
<p class="font-sm content-color">您的訂單已成功下達您的訂單編號為#{{ order_sn }}</p>
</div>
</section>
<!-- Banner Section End -->
</main>
<!-- Main End -->
</template>
<script setup>
import { onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { onMounted } from "vue";
import { useRoute } from "vue-router";
// import { linePay } from '@/services/order'
const route = useRoute()
const route = useRoute();
const order_sn = route.query.sn
const pay_id = route.query.pay_id
const order_sn = route.query.order_sn;
onMounted(async () => {
if(order_sn){
// let res = await linePay({order_sn})
// if(res.code === 200){
// window.location.href = res.data.info.paymentUrl.web
// }
// console.log('res',res.data.paymentUrl.web)
}
})
if (order_sn) {
// let res = await linePay({order_sn})
// if(res.code === 200){
// window.location.href = res.data.info.paymentUrl.web
// }
// console.log('res',res.data.paymentUrl.web)
}
});
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

@ -1,305 +1,463 @@
<template>
<!-- Header Start -->
<header class="header">
<div class="logo-wrap">
<i class="icon-arrow-left-bold-box icli" @click="$router.go(-1)"></i>
<h1 class="title-color font-md">商品結帳
<span class="font-sm content-color">({{ cartStore.cartNum }} 樣商品)</span>
</h1>
</div>
<div class="avatar-wrap" @click="$router.push('/home')">
<i class="icon-home icli"></i>
</div>
</header>
<!-- Header End -->
<!-- Main Start -->
<main class="main-wrap payment-page cart-page mb-xxl">
<div class="cartitem-list">
<div>
訂單詳細
</div>
<div>
<van-button type="success" size="mini" @click="$router.push('/cart')"></van-button>
</div>
</div>
<!-- Cart Item Section Start -->
<div class="cart-item-wrap pt-0">
<div class="swipe-to-show" v-for="item in items" :key="item.rec_id">
<div class="product-list media">
<a href="javascript:void(0);">
<img :src="`https://shop.h888.fun/${item.goods_thumb}`" alt="offer" />
</a>
<div class="media-body">
<a href="product.html" class="font-sm"> {{ item.goods_name }} </a>
<span class="price-color font-sm">${{ item.goods_price }}</span>
<div class="plus-minus">
X {{ item.goods_number }}
</div>
</div>
<!-- Header Start -->
<header class="header">
<div class="logo-wrap">
<i class="icon-arrow-left-bold-box icli" @click="$router.go(-1)"></i>
<h1 class="title-color font-md">
商品結帳
<span class="font-sm content-color">({{ cartStore.cartNum }} 樣商品)</span>
</h1>
</div>
<div class="avatar-wrap" @click="$router.push('/home')">
<i class="icon-home icli"></i>
</div>
</div>
</div>
<!-- Cart Item Section End -->
</header>
<!-- Address Section Start -->
<!-- Header End -->
<div class="address-block">
<div>
<div>
收貨人: wayne
<!-- Main Start -->
<main class="main-wrap payment-page cart-page mb-xxl">
<div class="cartitem-list">
<div>訂單詳細</div>
<div></div>
</div>
<div>
收貨地址: 台北市
<!-- Cart Item Section Start -->
<div class="cart-item-wrap pt-0">
<div class="swipe-to-show" v-for="item in items" :key="item.rec_id">
<div class="product-list media">
<a href="javascript:void(0);">
<img :src="`https://shop.h888.fun/${item.goods_thumb}`" alt="offer" />
</a>
<div class="media-body">
<a href="product.html" class="font-sm"> {{ item.goods_name }} </a>
<span class="price-color font-sm">${{ item.goods_price }}</span>
<div class="plus-minus">X {{ item.goods_number }}</div>
</div>
</div>
</div>
</div>
</div>
<div>
<van-button type="success" size="mini" @click="$router.replace('/address')"></van-button>
</div>
</div>
<!-- Address Section End -->
<!-- Cart Item Section End -->
<!-- <button class="d-block btn-outline-grey" data-bs-toggle="offcanvas" data-bs-target="#add-card"
<!-- <button class="d-block btn-outline-grey" data-bs-toggle="offcanvas" data-bs-target="#add-card"
aria-controls="add-card">+ Add New Card</button> -->
<!-- Payment Section Start -->
<section class="payment-section">
<!-- Payment Method Accordian Start -->
<div class="accordion" id="accordionExample">
<!-- Accordion Start -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button class="accordion-button font-md title-color" type="button" data-bs-toggle="collapse"
data-bs-target="#shipping" aria-expanded="false" aria-controls="shipping">
配送方式
</button>
</h2>
<div id="shipping" class="accordion-collapse collapse show" aria-labelledby="headingTwo"
data-bs-parent="#accordionExample">
<div class="accordion-body net-banking">
<div class="row">
<!-- Shipping Option Start -->
<div class="input-box col-6" v-for="(v, index) in shippingList" :key="index">
<input type="radio" name="shipping" id="jpm-moro" :value="index" v-model="order.shipping" />
<label class="form-check-label" for="jpm-moro">{{ v.shipping_name }}</label>
<!-- Payment Section Start -->
<section class="payment-section">
<!-- Payment Method Accordian Start -->
<div class="accordion" id="accordionShipping">
<!-- Accordion Start -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button
class="accordion-button font-md title-color"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
data-bs-target="#shipping"
aria-controls="shipping"
>
配送方式
</button>
</h2>
<div
id="shipping"
class="accordion-collapse collapse show"
aria-labelledby="headingOne"
data-bs-parent="#accordionShipping"
>
<div class="accordion-body">
<ul class="filter-row">
<li
class="filter-col"
:class="{ active: shippingData.shipping_code === v.shipping_code }"
@click="selectShipping(v)"
v-for="(v, index) in shippingList"
:key="index"
>
{{ v.shipping_name }}
<span class="check"><img src="@/assets/icons/svg/active.svg" alt="active" /></span>
</li>
</ul>
</div>
<div v-show="showExtra" class="shipping-data">
<template v-if="shippingData.shipping_code == 'shipping'">
<div>
<ul>
<li>收件人{{ shippingData.extra_data.consignee }}</li>
<li> {{ shippingData.extra_data.address }}</li>
<li> {{ shippingData.extra_data.tel }}</li>
</ul>
</div>
</template>
<template v-else-if="shippingData.shipping_code == 'ecpay'">
<div>
<ul v-if="shippingData.extra_data.type">
<li>
{{
logisticType[shippingData.extra_data.type] +
" " +
shippingData.extra_data.store_name
}}
</li>
<li> {{ shippingData.extra_data.store_address }}</li>
<li> {{ shippingData.extra_data.store_tel }}</li>
</ul>
</div>
</template>
<div>
<van-button type="success" size="mini" @click="changeShipping"></van-button>
</div>
</div>
</div>
</div>
<!-- Shipping Option End -->
</div>
<!-- Accordion End -->
</div>
</div>
</div>
<!-- Accordion End -->
<!-- Accordion Start -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button class="accordion-button font-md title-color" type="button" data-bs-toggle="collapse"
data-bs-target="#payment" aria-expanded="true" aria-controls="payment">
支付方式
</button>
</h2>
<div id="payment" class="accordion-collapse collapse show" aria-labelledby="headingOne"
data-bs-parent="#accordionExample">
<div class="accordion-body">
<ul class="filter-row">
<li class="filter-col" :class="{ active: order.payment === v.pay_id }" @click="selectPayment(v.pay_id)"
v-for="(v, index) in paymentList" :key="index">
<img class="payment-card" :src="v.logo" :alt="v.pay_name" />
{{ v.pay_name }}
<span class="check"><img src="@/assets/icons/svg/active.svg" alt="active" /></span>
</li>
</ul>
<div class="accordion" id="accordionExample">
<!-- Accordion Start -->
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button
class="accordion-button font-md title-color"
type="button"
data-bs-toggle="collapse"
data-bs-target="#payment"
aria-expanded="true"
aria-controls="payment"
>
支付方式
</button>
</h2>
<div
id="payment"
class="accordion-collapse collapse show"
aria-labelledby="headingOne"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
<ul class="filter-row">
<li
class="filter-col"
:class="{ active: orderStore.payment.pay_code === 'cod' }"
v-if="orderStore.shipping.shipping_code === 'ecpay'"
@click="selectPayment({ pay_id: 0, pay_code: 'cod', pay_name: '貨到付款' })"
>
貨到付款
<span class="check"><img src="@/assets/icons/svg/active.svg" alt="active" /></span>
</li>
<li
class="filter-col"
:class="{ active: orderStore.payment.pay_code === v.pay_code }"
@click="selectPayment(v)"
v-for="(v, index) in paymentList"
:key="index"
>
<img class="payment-card" :src="v.logo" :alt="v.pay_name" />
{{ v.pay_name }}
<span class="check"><img src="@/assets/icons/svg/active.svg" alt="active" /></span>
</li>
</ul>
</div>
</div>
</div>
<!-- Accordion End -->
</div>
</div>
</div>
<!-- Accordion End -->
</div>
<!-- Payment Method Accordian End -->
</section>
<!-- Payment Section End -->
<!-- Order Detail Start -->
<section class="order-detail">
<h3 class="title-2">訂單詳細</h3>
<!-- Product Detail Start -->
<ul>
<li>
<span>金額</span>
<span>${{ detail.sum }}</span>
</li>
<li>
<span>折扣</span>
<span class="font-theme">-${{ detail.discount }}</span>
</li>
<!-- <li>
<!-- Payment Method Accordian End -->
</section>
<!-- Payment Section End -->
<!-- Order Detail Start -->
<section class="order-detail">
<h3 class="title-2">訂單詳細</h3>
<!-- Product Detail Start -->
<ul>
<li>
<span>金額</span>
<span>${{ detail.sum_amount }}</span>
</li>
<li>
<span>折扣</span>
<span class="font-theme">-${{ detail.discount }}</span>
</li>
<!-- <li>
<span>折價卷</span>
<a href="javascript:void(0);" class="font-danger">Apply Coupon</a>
</li> -->
<li v-show="detail.pay_fee > 0">
<span>金流手續費</span>
<span>{{ detail.pay_fee }}</span>
</li>
<li v-show="detail.shipping_fee > 0">
<span>運費</span>
<span>{{ detail.shipping_fee }}</span>
</li>
<li>
<span>運費</span>
<span>{{ detail.shipping }}</span>
</li>
<li>
<span>總金額</span>
<span>${{ detail.total }}</span>
</li>
</ul>
<!-- Product Detail End -->
</section>
<!-- Order Detail End -->
</main>
<!-- Main End -->
<!-- Footer Start -->
<footer class="footer-wrap footer-button">
<a href="javascript:void(0);" class="font-md" @click="handleFinish"></a>
</footer>
<!-- Footer End -->
<li>
<span>總金額</span>
<span>${{ detail.total_amount }}</span>
</li>
</ul>
<!-- Product Detail End -->
</section>
<!-- Order Detail End -->
</main>
<!-- Main End -->
<!-- Footer Start -->
<footer class="footer-wrap footer-button">
<a href="javascript:void(0);" class="font-md" @click="handleFinish"></a>
</footer>
<!-- Footer End -->
</template>
<script setup>
import _ from 'lodash'
import { ref, reactive, onMounted, computed } from 'vue'
import { useCartStore } from '@/store/Cart'
import _ from "lodash";
import { ref, reactive, onMounted, computed } from "vue";
import { useCartStore } from "@/store/Cart";
import { useOrderStore } from "@/store/Order";
import { storeToRefs } from "pinia";
import { showToast } from "vant";
import { showToast } from 'vant'
import { addOrder } from '@/services/order'
import { getPayments } from '@/services/payment'
import { getShippings } from '@/services/shipping'
import router from '@/router';
import { addOrder } from "@/services/order";
import linepayicon from '/src/assets/icons/png/linepay.png'
import mastericon from '/src/assets/icons/png/mastercard1.png'
import { getPayments } from "@/services/payment";
import { getShippings, getUserDefaultCvs } from "@/services/shipping";
import { getUserDefaultAddress } from "@/services/user";
import router from "@/router";
import linepayicon from "/src/assets/icons/png/linepay.png";
import mastericon from "/src/assets/icons/png/mastercard1.png";
const cartStore = useCartStore();
const orderStore = useOrderStore();
const cartStore = useCartStore()
const { cartItems: items } = storeToRefs(cartStore);
const { goodsItems: items } = storeToRefs(orderStore);
const order = reactive({
payment: 0,
shipping: 0,
goods: []
})
const paymentList = ref([])
const shippingList = ref([])
onMounted(async()=>{
let res1 = await getPayments()
if(res1.code === 200){
paymentList.value = res1.data
}
let res2 = await getShippings()
if(res2.code === 200){
shippingList.value = res2.data
}
})
payment: 0,
shipping: 0,
goods: [],
});
const paymentList = ref([]);
const shippingList = ref([]);
const logisticType = {
1: "711",
2: "全家",
3: "萊爾富",
4: "OK",
};
onMounted(async () => {
cartToOrder();
let res1 = await getPayments();
if (res1.code === 200) {
paymentList.value = res1.data;
}
let res2 = await getShippings();
if (res2.code === 200) {
shippingList.value = res2.data;
}
});
//
const cartToOrder = () => {
orderStore.goodsItems = cartStore.cartItems;
};
//
const selectShipping = async (value) => {
if (shippingData.value.shipping_code === value.shipping_code) return;
switch (value.shipping_code) {
case "shipping":
let resAddr = await getUserDefaultAddress();
if (resAddr.code === 200) {
orderStore.shipping = {
shipping_code: value.shipping_code,
shipping_id: value.shipping_id,
shipping_fee: 0,
extra_data: {
address: resAddr.data.address,
consignee: resAddr.data.consignee,
tel: resAddr.data.tel,
},
};
} else {
orderStore.shipping = {
shipping_code: value.shipping_code,
shipping_id: value.shipping_id,
shipping_fee: 0,
extra_data: {},
};
router.push("/address?from=order");
}
break;
case "ecpay":
let res = await getUserDefaultCvs();
if (res.code === 200) {
orderStore.shipping = {
shipping_code: value.shipping_code,
shipping_id: value.shipping_id,
shipping_fee: 0,
extra_data: {
type: res.data.type,
store_id: res.data.store_id,
store_name: res.data.store_name,
store_address: res.data.store_address,
store_tel: res.data.store_tel,
},
};
} else {
orderStore.shipping = {
shipping_code: value.shipping_code,
shipping_id: value.shipping_id,
shipping_fee: 0,
extra_data: {},
};
router.push("/order/shipping");
}
break;
default:
break;
}
};
const changeShipping = () => {
switch (shippingData.value.shipping_code) {
case "ecpay":
router.push("/order/shipping");
break;
case "shipping":
router.push("/address?from=order");
break;
default:
break;
}
};
const shippingData = computed(() => {
return orderStore.shipping;
});
//
const showExtra = computed(() => {
let is_empty = _.isEmpty(orderStore.shipping.extra_data);
if (is_empty) {
return false;
} else {
return true;
}
});
//
const selectPayment = (value) => {
order.payment = value
}
orderStore.payment = {
pay_code: value.pay_code,
pay_id: value.pay_id,
pay_fee: 0,
};
};
//
const handleFinish = async () => {
order.goods = items.value
let res = await addOrder(order)
if (res.code === 200) {
//
cartStore.clearCart()
// window.location.href = res.data.info.paymentUrl.web
// console.log('resdata',res.data)
return router.replace({
name: 'Payment',
query: {
order_sn: res.data.order_sn,
pay_code: res.data.pay_code
}
})
}
return showToast('操作失敗')
}
let order = orderStore.$state;
order = { ...order, goods_amount: orderStore.sum_amount, order_amount: orderStore.total_amount };
let res = await addOrder(order);
if (res.code === 200) {
//
cartStore.clearCart();
// window.location.href = res.data.info.paymentUrl.web
// console.log('resdata',res.data)
return router.replace({
name: "Payment",
query: {
order_sn: res.data.order_sn,
pay_code: res.data.pay_code,
},
});
}
return showToast("操作失敗");
};
//
const detail = computed(() => {
let sum = items.value.reduce((accumulator, value) => {
return accumulator + (value.goods_price * value.goods_number)
}, 0)
let discount = 0
let shipping = 0
let total = sum - discount + shipping
return { sum, discount, shipping, total }
})
let sum_amount = orderStore.sum_amount;
let discount = orderStore.discount;
let shipping_fee = orderStore.shipping.shipping_fee;
let pay_fee = orderStore.payment.pay_fee;
let total_amount = orderStore.total_amount;
return { sum_amount, discount, shipping_fee, pay_fee, total_amount };
});
</script>
<style lang="less" scoped>
.cart-item-wrap {
margin-bottom: 20px;
margin-bottom: 20px;
}
.delete-button {
i {
font-size: 20px;
color: #FFFFFF;
}
i {
font-size: 20px;
color: #ffffff;
}
}
.cartitem-list {
width: 100%;
border: 1px #cacaca solid;
border-radius: 5px;
height: 45px;
display: flex;
justify-content: space-between;
align-items: center;
div:nth-child(1) {
color: red;
padding-left: 10px;
}
div:nth-child(2) {
padding-right: 10px;
}
width: 100%;
border: 1px #cacaca solid;
border-radius: 5px;
height: 45px;
display: flex;
justify-content: space-between;
align-items: center;
div:nth-child(1) {
color: red;
padding-left: 10px;
}
div:nth-child(2) {
padding-right: 10px;
}
}
.price-color {
color: red;
color: red;
}
.filter-row {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
.filter-col {
width: 40%;
.filter-col {
width: 40%;
}
}
}
//
.shipping-data {
display: flex;
padding: 10px 15px;
align-items: center;
justify-content: space-between;
div:nth-child(1) {
flex: 1;
// padding: 10px 0;
// border-bottom: 1px #cacaca solid;
}
div:nth-child(2) {
width: 40px;
i {
font-size: 20px;
color: #cacaca;
}
}
}
</style>

@ -1,137 +1,140 @@
<template>
<!-- Main Start -->
<main class="main-wrap order-success-page mb-xxl">
<!-- Banner Section Start -->
<section class="banner-section">
<div class="banner-wrap">
<img src="@/assets/svg/order-success.svg" alt="order-success" />
</div>
<div class="content-wrap">
<h1 class="font-lg title-color">感謝您的購買</h1>
<p class="font-sm content-color">您的訂單已成功下達您的訂單編號為#{{ order_sn }}</p>
</div>
<div ref="formContainer" :style="{display: showForm}">
</div>
<div v-show="showTappay">
<form class="ui form">
<div class="field">
<label>信用卡</label>
<div id="tappay-iframe"></div>
</div>
</form>
<br>
<div class="ui button" id="submit" @click="onTapPay"></div>
</div>
</section>
<!-- Banner Section End -->
<!-- Banner Section Start -->
<section class="banner-section">
<div class="banner-wrap">
<img src="@/assets/svg/order-success.svg" alt="order-success" />
</div>
<div class="content-wrap">
<h1 class="font-lg title-color">感謝您的購買</h1>
<p class="font-sm content-color">您的訂單已成功下達您的訂單編號為#{{ order_sn }}</p>
</div>
<div ref="formContainer" :style="{ display: showForm }"></div>
<div v-show="showTappay">
<form class="ui form">
<div class="field">
<label>信用卡</label>
<div id="tappay-iframe"></div>
</div>
</form>
<br />
<div class="ui button" id="submit" @click="onTapPay"></div>
</div>
</section>
<!-- Banner Section End -->
</main>
<!-- Main End -->
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { payment } from '@/services/order'
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { payment } from "@/services/order";
const statusTable = {
'0': '欄位已填好,並且沒有問題',
'1': '欄位還沒有填寫',
'2': '欄位有錯誤,此時在 CardView 裡面會用顯示 errorColor',
'3': '使用者正在輸入中',
}
0: "欄位已填好,並且沒有問題",
1: "欄位還沒有填寫",
2: "欄位有錯誤,此時在 CardView 裡面會用顯示 errorColor",
3: "使用者正在輸入中",
};
const defaultCardViewStyle = {
color: 'rgb(0,0,0)',
fontSize: '15px',
lineHeight: '24px',
fontWeight: '300',
errorColor: 'red',
placeholderColor: ''
}
color: "rgb(0,0,0)",
fontSize: "15px",
lineHeight: "24px",
fontWeight: "300",
errorColor: "red",
placeholderColor: "",
};
const config = {
isUsedCcv: false,
//
isMaskCreditCardNumber: true,
maskCreditCardNumberRange: {
beginIndex: 6,
endIndex: 11
}
}
isUsedCcv: false,
//
isMaskCreditCardNumber: true,
maskCreditCardNumberRange: {
beginIndex: 6,
endIndex: 11,
},
};
const route = useRoute()
const route = useRoute();
const order_sn = route.query.order_sn
const pay_code = route.query.pay_code
const order_sn = route.query.order_sn;
const pay_code = route.query.pay_code;
const returnData = ref(null)
const formContainer = ref()
const showForm = ref('none')
const showTappay = ref(false)
const returnData = ref(null);
const formContainer = ref();
const showForm = ref("none");
const showTappay = ref(false);
onMounted(async () => {
if(order_sn && pay_code && pay_code !== 'tpcredit'){
let res = await payment({order_sn,pay_code})
if(res.code === 200){
//fromformContainersubmit
if(res.data.method === 'post'){
formContainer.value.innerHTML = res.data.data
if(showForm.value === 'none'){
formContainer.value.querySelector('form').submit()
if (order_sn && pay_code) {
switch (pay_code) {
case "tpcredit":
showTappay.value = true;
TPDirect.setupSDK(
128084,
"app_Mmp6jV9pguSBO8eRwHOOf0hxKljbeQeZEKsl9Ow8hEbOMK5FIkLb7bpvenaS",
"sandbox"
);
TPDirect.card.setup("#tappay-iframe", defaultCardViewStyle, config);
break;
case "linepay":
default:
let res = await payment({ order_sn, pay_code });
if (res.code === 200) {
//fromformContainersubmit
if (res.data.method === "post") {
formContainer.value.innerHTML = res.data.data;
if (showForm.value === "none") {
formContainer.value.querySelector("form").submit();
}
} else if (res.data.method === "redirect") {
window.location.href = res.data.data.paymentUrl.web;
}
}
break;
}
}else if(res.data.method === 'redirect'){
window.location.href = res.data.data.paymentUrl.web
}
}
}else if(order_sn && pay_code && pay_code === 'tpcredit'){
showTappay.value = true
TPDirect.setupSDK(128084, 'app_Mmp6jV9pguSBO8eRwHOOf0hxKljbeQeZEKsl9Ow8hEbOMK5FIkLb7bpvenaS', 'sandbox')
TPDirect.card.setup('#tappay-iframe', defaultCardViewStyle, config)
}
})
});
const onTapPay = () => {
TPDirect.card.getPrime(async (result) => {
if (result.status !== 0) {
alert('get prime error ' + result.msg)
return
}
console.log('get prime 成功prime: ' + result.card.prime)
// returnData.value = result.card.prime
let res = await payment({pay_id:19,order_sn, prime:result.card.prime})
console.log('res',res)
})
}
TPDirect.card.getPrime(async (result) => {
if (result.status !== 0) {
alert("get prime error " + result.msg);
return;
}
console.log("get prime 成功prime: " + result.card.prime);
// returnData.value = result.card.prime
let res = await payment({ pay_id: 19, order_sn, prime: result.card.prime });
console.log("res", res);
});
};
TPDirect.card.onUpdate(function (update) {
console.log('update',update)
})
console.log("update", update);
});
</script>
<style lang="less" scoped>
#tappay-iframe {
font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;
margin: 0;
outline: 0;
line-height: 1.21428571em;
padding: .578571em 1em;
font-size: 1em;
background: #fff;
border: 1px solid rgba(34,36,38,.15);
color: rgba(0,0,0,.87);
border-radius: .28571429rem;
box-shadow: 0 0 0 0 transparent inset;
transition: color .1s ease,border-color .1s ease;
width: 100%;
font-family: Lato, "Helvetica Neue", Arial, Helvetica, sans-serif;
margin: 0;
outline: 0;
line-height: 1.21428571em;
padding: 0.578571em 1em;
font-size: 1em;
background: #fff;
border: 1px solid rgba(34, 36, 38, 0.15);
color: rgba(0, 0, 0, 0.87);
border-radius: 0.28571429rem;
box-shadow: 0 0 0 0 transparent inset;
transition: color 0.1s ease, border-color 0.1s ease;
width: 100%;
}
</style>

@ -0,0 +1,164 @@
<template>
<van-nav-bar title="超商取貨" left-text="" left-arrow @click-left="$router.replace('/checkout')" />
<main class="main-wrap shipping-page">
<van-collapse v-model="activeNames" accordion>
<van-radio-group v-model="shippingId">
<van-collapse-item title="7-ELEVEN" name="1">
<div>
<div class="logistic-block" v-for="v in myShipping[1]">
<div>
<van-radio :name="v.store_id" @click="handleChange(v)"
>{{ v.store_name }}<br />{{ v.store_address }}<br />{{ v.store_tel }}</van-radio
>
</div>
<div v-if="shippingId !== v.store_id">
<i class="icon-trash" @click="handleDeleteLogistic(v.id)"></i>
</div>
</div>
<van-button plain type="success" block @click="handleGetMap(1)">+</van-button>
</div>
</van-collapse-item>
<van-collapse-item title="全家" name="2">
<div>
<div class="logistic-block" v-for="v in myShipping[2]">
<div>
<van-radio :name="v.store_id" @click="handleChange(v)"
>{{ v.store_name }}<br />{{ v.store_address }}<br />{{ v.store_tel }}</van-radio
>
</div>
<div v-if="shippingId !== v.store_id">
<i class="icon-trash" @click="handleDeleteLogistic(v.id)"></i>
</div>
</div>
<van-button plain type="success" block @click="handleGetMap(2)">+</van-button>
</div>
</van-collapse-item>
<van-collapse-item title="萊爾富" name="3">
<div>
<div class="logistic-block" v-for="v in myShipping[3]">
<div>
<van-radio :name="v.store_id" @click="handleChange(v)"
>{{ v.store_name }}<br />{{ v.store_address }}<br />{{ v.store_tel }}</van-radio
>
</div>
<div v-if="shippingId !== v.store_id">
<i class="icon-trash" @click="handleDeleteLogistic(v.id)"></i>
</div>
</div>
<van-button plain type="success" block @click="handleGetMap(3)">+</van-button>
</div>
</van-collapse-item>
<van-collapse-item title="OK Mart" name="4">
<div>
<div class="logistic-block" v-for="v in myShipping[4]">
<div>
<van-radio :name="v.store_id" @click="handleChange(v)"
>{{ v.store_name }}<br />{{ v.store_address }}<br />{{ v.store_tel }}</van-radio
>
</div>
<div v-if="shippingId !== v.store_id">
<i class="icon-trash" @click="handleDeleteLogistic(v.id)"></i>
</div>
</div>
<van-button plain type="success" block @click="handleGetMap(4)">+</van-button>
</div>
</van-collapse-item>
</van-radio-group>
</van-collapse>
</main>
<div ref="formContainer" :style="{ display: showForm }"></div>
<footer class="footer-wrap footer-button">
<a href="javascript:void(0);" class="font-md">確認</a>
</footer>
</template>
<script setup>
import { ref, watch, onMounted } from "vue";
import { getMap, getMyCvs, deleteLogistic } from "@/services/shipping";
import { useOrderStore } from "@/store/Order";
import { showToast } from "vant";
import { useRoute, useRouter } from "vue-router";
const orderStore = useOrderStore();
const router = useRouter();
const route = useRoute();
const showForm = ref("none");
const formContainer = ref();
const activeNames = ref("1");
const shippingId = ref("");
const myShipping = ref([]);
onMounted(async () => {
let res = await getMyCvs();
if (res.code === 200) {
shippingId.value = res.data.default.store_id;
activeNames.value = res.data.default.type;
myShipping.value = res.data.data;
orderStore.initShippingData(res.data.default);
if (route.query.is_return == 1) {
router.replace("/checkout");
}
}
});
const handleChange = (store) => {
let res = orderStore.setDefaultStoreID(store);
if (!res) {
showToast("操作失敗");
shippingId.value = oVal;
}
router.replace("/checkout");
};
const handleDeleteLogistic = async (id) => {
let res = await deleteLogistic(id);
if (res.code === 200) {
showToast("刪除成功");
let res = await getMyCvs();
if (res.code === 200) {
shippingId.value = res.data.default.store_id;
activeNames.value = res.data.default.type;
myShipping.value = res.data.data;
}
}
};
const handleGetMap = async (type) => {
let res = await getMap({ type });
if (res.code === 200) {
console.log(formContainer.value);
formContainer.value.innerHTML = res.data;
if (showForm.value === "none") {
formContainer.value.querySelector("form").submit();
}
}
};
</script>
<style lang="less" scoped>
.van-radio {
margin: 15px 0;
}
.shipping-page {
padding-bottom: 50px;
}
.logistic-block {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
div:nth-child(2) {
i {
font-size: 20px;
}
}
}
</style>

@ -1,93 +1,101 @@
<template>
<!-- Main Start -->
<main class="main-wrap login-page mb-xxl">
<!-- Login Section Start -->
<section class="login-section p-0">
<!-- Login Form Start -->
<form class="custom-form">
<h1 class="font-md title-color fw-600">會員登入</h1>
<!-- Login Section Start -->
<section class="login-section p-0">
<!-- Login Form Start -->
<form class="custom-form">
<h1 class="font-md title-color fw-600">會員登入</h1>
<!-- Email Input start -->
<div class="input-box">
<input type="tel" placeholder="手機號碼" required class="form-control" v-model="form.username" />
<i data-feather="at-sign"></i>
</div>
<!-- Email Input End -->
<!-- Email Input start -->
<div class="input-box">
<input type="tel" placeholder="手機號碼" required class="form-control" v-model="form.username"/>
<i data-feather="at-sign"></i>
</div>
<!-- Email Input End -->
<!-- Password Input start -->
<div class="input-box">
<input
type="password"
placeholder="登入密碼"
required
class="form-control"
v-model="form.password"
/>
<i class="iconly-Hide icli showHidePassword"></i>
</div>
<!-- Password Input End -->
<a href="javascript:void(0)" class="content-color font-sm forgot mb-3">忘記密碼 ?</a>
<button type="button" class="btn-solid" @click="handleLogin"></button>
<span class="content-color font-sm d-block text-center fw-600"
>還沒有帳號 <router-link to="/register" class="underline">立即註冊 </router-link></span
>
</form>
<!-- Login Form End -->
<!-- Password Input start -->
<div class="input-box">
<input type="password" placeholder="登入密碼" required class="form-control" v-model="form.password"/>
<i class="iconly-Hide icli showHidePassword"></i>
</div>
<!-- Password Input End -->
<a href="javascript:void(0)" class="content-color font-sm forgot mb-3">忘記密碼 ?</a>
<button type="button" class="btn-solid" @click="handleLogin"></button>
<span class="content-color font-sm d-block text-center fw-600">還沒有帳號 <router-link to="/register" class="underline">立即註冊 </router-link></span>
</form>
<!-- Login Form End -->
<!-- Social Section Start -->
<div class="socila-section">
<span>
<span class="font-sm fw-600 font-theme"> 其他登入方式 </span>
</span>
<div class="social-wrap">
<a href="javascript:void(0)" class="font-md title-color fw-600" @click.prevent="handleLineLogin">
<img src="@/assets/icons/png/line.png" alt="line login" /> Line 登入 </a>
<!-- <a href="https://accounts.google.com/ServiceLogin" class="font-md title-color fw-600"><img src="@/assets/icons/png/google.png" alt="phone" /> Continue with Google </a> -->
</div>
</div>
<!-- Social Section End -->
</section>
<!-- Login Section End -->
<!-- Social Section Start -->
<div class="socila-section">
<span>
<span class="font-sm fw-600 font-theme"> 其他登入方式 </span>
</span>
<div class="social-wrap">
<a href="javascript:void(0)" class="font-md title-color fw-600" @click.prevent="handleLineLogin">
<img src="@/assets/icons/png/line.png" alt="line login" /> Line 登入
</a>
<!-- <a href="https://accounts.google.com/ServiceLogin" class="font-md title-color fw-600"><img src="@/assets/icons/png/google.png" alt="phone" /> Continue with Google </a> -->
</div>
</div>
<!-- Social Section End -->
</section>
<!-- Login Section End -->
</main>
<!-- Main End -->
</template>
<script setup>
import Cookies from 'js-cookie'
import Cookies from "js-cookie";
// import liff from '@line/liff'
import { ref } from 'vue'
import { useRoute , useRouter } from 'vue-router'
import { ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { login } from '@/services/auth'
import { login } from "@/services/auth";
const route = useRoute();
const router = useRouter();
console.log('callback')
console.log("callback");
const form = ref({
username:'0983214434',
password:'123456'
})
username: "0983214434",
password: "123456",
});
const handleLogin = async ()=>{
let res = await login(form.value)
console.log('res',res)
if(res.code === 200){
Cookies.set('token',res.data.token,{ expires: 30 ,domain: import.meta.env.VITE_APP_SSO_DOMAIN})
Cookies.set('uid',res.data.uid,{ expires: 30 ,domain: import.meta.env.VITE_APP_SSO_DOMAIN})
const handleLogin = async () => {
let res = await login(form.value);
// console.log("res", res);
if (res.code === 200) {
Cookies.set("token", res.data.token, { expires: 30, domain: import.meta.env.VITE_APP_SSO_DOMAIN });
Cookies.set("uid", res.data.uid, { expires: 30, domain: import.meta.env.VITE_APP_SSO_DOMAIN });
router.push('/user')
}
}
router.push("/user");
} else if (res.code === 201) {
router.push("/register");
}
};
const handleLineLogin = async () => {
const client_id = '1657876696'
const redirect_uri = import.meta.env.VITE_APP_BASE_URL +'/m/linelogin/'
let link = 'https://access.line.me/oauth2/v2.1/authorize?'
link = link + 'response_type=code'
link += '&client_id=' + client_id
link += '&redirect_uri=' + redirect_uri
link += '&state=login'
link += '&scope=openid%20profile'
window.location.href = link
}
const client_id = "1657876696";
const redirect_uri = import.meta.env.VITE_APP_BASE_URL + "/m/linelogin/";
let link = "https://access.line.me/oauth2/v2.1/authorize?";
link = link + "response_type=code";
link += "&client_id=" + client_id;
link += "&redirect_uri=" + redirect_uri;
link += "&state=login";
link += "&scope=openid%20profile";
window.location.href = link;
};
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

@ -1,79 +1,64 @@
<template>
<!-- Main Start -->
<main class="main-wrap setting-page mb-xxl">
<div class="user-panel">
<div class="media">
<div class="avatar-wrap">
<a href="javascript:void(0)"> <img src="@/assets/images/avatar/avatar.jpg" alt="avatar" /></a>
<span class="edit"> <i class="icon-pencil"></i></span>
</div>
<div class="media-body">
<h2 class="title-color">Wayne</h2>
</div>
<div class="user-panel">
<div class="media">
<div class="avatar-wrap">
<a href="javascript:void(0)">
<img :src="form.headimg" alt="avatar" />
</a>
<span class="edit"> <i class="icon-pencil"></i></span>
</div>
<div class="media-body">
<h2 class="title-color">{{ form.real_name }}</h2>
</div>
</div>
</div>
</div>
<!-- Form Section Start -->
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field
v-model="form.alias"
name="alias"
placeholder="會員名稱"
/>
<van-field
v-model="form.email"
name="email"
placeholder="電子郵件"
/>
<van-field
v-model="form.mobile_phone"
name="mobile_phone"
placeholder="行動電話"
/>
<van-field
v-model="form.birthday"
is-link
readonly
name="datePicker"
placeholder="點擊選擇生日"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-date-picker @confirm="onConfirm" @cancel="showPicker = false" />
</van-popup>
<van-field name="sex">
<template #input>
<van-radio-group v-model="form.sex" direction="horizontal">
<van-radio name="0" value="0">保密</van-radio>
<van-radio name="1" value="1"></van-radio>
<van-radio name="2" value="2"></van-radio>
</van-radio-group>
</template>
</van-field>
</van-cell-group>
<div style="margin: 16px;">
<van-button round block color="#0baf9a" native-type="submit">
提交
</van-button>
</div>
</van-form>
<!-- Form Section End -->
<!-- Form Section Start -->
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field v-model="form.real_name" name="real_name" placeholder="真實姓名" />
<van-field v-model="form.email" name="email" placeholder="電子郵件" />
<van-field v-model="form.mobile_phone" name="mobile_phone" placeholder="行動電話" />
<van-popup v-model:show="showPicker" position="bottom">
<van-date-picker @confirm="onConfirm" @cancel="showPicker = false" />
</van-popup>
</van-cell-group>
<div style="margin: 16px">
<van-button round block color="#0baf9a" native-type="submit"> 提交 </van-button>
</div>
</van-form>
<!-- Form Section End -->
</main>
<!-- Main End -->
</template>
<script setup>
import { ref } from 'vue'
import { ref, onMounted } from "vue";
import { getUserInfo } from "@/services/user";
const showPicker = ref(false)
const showPicker = ref(false);
const form = ref({
sex: '0'
})
</script>
sex: "0",
});
<style lang="less" scoped>
onMounted(async () => {
let res = await getUserInfo();
if (res.code == 200) {
form.value = {
real_name: res.data.real_name,
email: res.data.email,
mobile_phone: res.data.mobile_phone,
headimg: res.data.headimg,
};
}
});
const onSubmit = () => {
console.log(form.value);
};
</script>
</style>
<style lang="less" scoped></style>

@ -1,46 +1,49 @@
<template>
<div class="bg-pattern-wrap ratio2_1">
<!-- Background Image -->
<div class="bg-patter">
<!-- <img src="@/assets/images/banner/bg-pattern2.png" class="bg-img" alt="pattern" /> -->
</div>
<!-- Background Image -->
<div class="bg-patter">
<!-- <img src="@/assets/images/banner/bg-pattern2.png" class="bg-img" alt="pattern" /> -->
</div>
</div>
<!-- Main Start -->
<main class="main-wrap login-page mb-xxl">
<!-- <img class="logo" src="@/assets/images/logo/logo.png" alt="logo" />
<!-- <img class="logo" src="@/assets/images/logo/logo.png" alt="logo" />
<img class="logo logo-w" src="@/assets/images/logo/logo-w.png" alt="logo" /> -->
<p class="font-sm content-color">
</p>
<!-- Login Section Start -->
<section class="login-section p-0">
<!-- Login Form Start -->
<form class="custom-form" @submit.prevent="onSubmit">
<h1 class="font-md title-color fw-600">加入會員</h1>
<!-- Email Input start -->
<div class="input-box">
<input type="text" placeholder="行動電話" v-model="form.phone" required class="form-control" />
<i class="icon-cellphone icli"></i>
</div>
<!-- Email Input End -->
<!-- Password Input start -->
<!-- <div class="input-box">
<p class="font-sm content-color"></p>
<!-- Login Section Start -->
<section class="login-section p-0">
<!-- Login Form Start -->
<form class="custom-form" @submit.prevent="onSubmit">
<h1 class="font-md title-color fw-600">加入會員</h1>
<div class="input-box">
<input type="text" placeholder="真實姓名" v-model="form.name" required class="form-control" />
<i class="icon-cellphone icli"></i>
</div>
<div class="input-box">
<input type="text" placeholder="行動電話" v-model="form.phone" required class="form-control" />
<i class="icon-cellphone icli"></i>
</div>
<div class="input-box">
<input type="text" placeholder="Email" v-model="form.email" required class="form-control" />
<i class="icon-cellphone icli"></i>
</div>
<!-- Password Input start -->
<!-- <div class="input-box">
<input type="password" placeholder="登入密碼" required class="form-control" />
<i class="icon-lock icli showHidePassword"></i>
</div> -->
<!-- Password Input End -->
<!-- Password Input End -->
<button type="submit" class="btn-solid">送出註冊</button>
<!-- <span class="content-color font-sm d-block text-center fw-600">已經有帳號了? <router-link to="/login" class="underline">登入 </router-link></span> -->
</form>
<!-- Login Form End -->
<button type="submit" class="btn-solid">送出註冊</button>
<!-- <span class="content-color font-sm d-block text-center fw-600">已經有帳號了? <router-link to="/login" class="underline">登入 </router-link></span> -->
</form>
<!-- Login Form End -->
<!-- Social Section Start -->
<!-- <div class="socila-section">
<!-- Social Section Start -->
<!-- <div class="socila-section">
<span>
<span class="font-sm fw-600 font-theme"> Or login with </span>
</span>
@ -49,63 +52,59 @@
<a href="https://accounts.google.com/ServiceLogin" class="font-md title-color fw-600"><img src="@/assets/icons/png/google.png" alt="phone" /> Continue with Google </a>
</div>
</div> -->
<!-- Social Section End -->
</section>
<!-- Login Section End -->
<!-- Social Section End -->
</section>
<!-- Login Section End -->
</main>
<!-- Main End -->
</template>
<script setup>
import axios from 'axios'
import Cookies from 'js-cookie'
import axios from "axios";
import Cookies from "js-cookie";
import { ref } from 'vue'
import { ref } from "vue";
import { useRouter, useRoute } from 'vue-router'
import { useRouter, useRoute } from "vue-router";
import { showToast, showLoadingToast } from 'vant'
import { showToast, showLoadingToast } from "vant";
import { register } from '@/services/auth'
import { register } from "@/services/auth";
const URL = window.URL || window.webkitURL;
const route = useRoute()
const router = useRouter()
const route = useRoute();
const router = useRouter();
const form = ref({
phone: ''
})
phone: "",
});
const onSubmit = async () => {
let { id_token } = JSON.parse(sessionStorage.getItem('line'))
showLoadingToast({
duration: 0,
message: '資料傳送中...',
forbidClick: true,
});
let regRes = await register({token: id_token , ...form.value})
if(regRes.code === 500){
showToast('line 登入已過期')
return router.push('/login')
}else if(regRes.code === 200){
showToast('註冊成功')
Cookies.set('token',regRes.data.token,{ expires: 30 ,domain: import.meta.env.VITE_APP_SSO_DOMAIN})
Cookies.set('uid',regRes.data.uid,{ expires: 30 ,domain: import.meta.env.VITE_APP_SSO_DOMAIN})
return router.push('/user')
}else{
showToast('註冊失敗')
return router.push('/login')
}
}
let { id_token } = JSON.parse(sessionStorage.getItem("line"));
showLoadingToast({
duration: 0,
message: "資料傳送中...",
forbidClick: true,
});
let regRes = await register({ token: id_token, ...form.value });
if (regRes.code === 500) {
showToast("line 登入已過期");
return router.push("/login");
} else if (regRes.code === 200) {
showToast("註冊成功");
Cookies.set("token", regRes.data.token, { expires: 30, domain: import.meta.env.VITE_APP_SSO_DOMAIN });
Cookies.set("uid", regRes.data.uid, { expires: 30, domain: import.meta.env.VITE_APP_SSO_DOMAIN });
return router.push("/user");
} else {
showToast("註冊失敗");
return router.push("/login");
}
};
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

@ -124,6 +124,11 @@ let routes = [
name: 'Checkout',
component: ()=> import("../pages/Cart/Checkout.vue")
},
{
path: '/order/shipping',
name: 'Shipping',
component: ()=> import("../pages/Cart/Shipping.vue"),
},
{
path: '/address',
name: 'Address',

@ -2,9 +2,13 @@ import { request } from '@/utils/request'
export function addOrder(params) {
return request('/order/add','post',params)
return request('/order/add', 'post', params)
}
export function payment(params) {
return request('/payment/process','post',params)
return request('/payment/process', 'post', params)
}
export function setDefaultStoreId(store_id) {
return request('/shipping/setDefaultStoreId', 'post', { store_id })
}

@ -1,5 +1,21 @@
import { request } from '@/utils/request'
export function getShippings() {
return request('/shipping/getShippings','get')
return request('/shipping/getShippings', 'get')
}
export function getMap(params) {
return request('/shipping/map', 'post', params)
}
export function getMyCvs() {
return request('/shipping/getMyCvs', 'get')
}
export function getUserDefaultCvs() {
return request('/shipping/getUserDefaultCvs', 'get')
}
export function deleteLogistic(id) {
return request('/shipping/deleteLogistic', 'get', { id })
}

@ -9,18 +9,22 @@ export function getUserAddress() {
}
export function addUserAddress(params) {
return request('/user/addUserAddress','post',params)
return request('/user/addUserAddress', 'post', params)
}
export function delUserAddress(id) {
return request('/user/delUserAddress','post', { id })
return request('/user/delUserAddress', 'post', { id })
}
export function setUserAddressDefault(id) {
return request('/user/setUserAddressDefault','post',{id})
return request('/user/setUserAddressDefault', 'post', { id })
}
export function getUserDefaultAddress() {
return request('/user/getUserDefaultAddress', 'get')
}
export function getUserOrders() {
return request('/user/getUserOrders','post')
return request('/user/getUserOrders', 'post')
}

@ -0,0 +1,64 @@
import { defineStore } from 'pinia'
import { setDefaultStoreId } from '@/services/order'
export const useOrderStore = defineStore('order', {
state: () => {
return {
payment: {
pay_id: null,
pay_code: '',
pay_fee: 0,
},
shipping: {
shipping_id: null,
shipping_code: '',
shipping_fee: 0,
extra_data: {
},
},
goodsItems: [],
discount: 0,
}
},
getters: {
total_amount() {
return this.sum_amount + this.shipping.shipping_fee + this.payment.pay_fee - this.discount
// return this.sum_amount + this.shipping.shipping_fee + this.payment.pay_fee - this.discount
},
sum_amount() {
let goods_total = this.goodsItems.reduce((total, item) => {
return total + item.goods_price * item.goods_number
}, 0)
return goods_total
}
},
actions: {
async initShippingData(params) {
this.shipping = {
shipping_code: 'ecpay',
extra_data: {
type: params.type,
store_id: params.store_id,
store_name: params.store_name,
store_address: params.store_address,
store_tel: params.store_tel
}
}
},
async setDefaultStoreID(params) {
let res = await setDefaultStoreId(params.store_id)
if (res.code !== 200) {
return false
}
this.shipping.extra_data = {
type: params.type,
store_id: params.store_id,
store_name: params.store_name,
store_address: params.store_address,
store_tel: params.store_tel
}
return true
}
},
})

@ -1,66 +1,70 @@
import axios from 'axios'
import Cookies from 'js-cookie'
import router from '@/router'
import { showToast, showLoadingToast } from 'vant'
const ajax = axios.create({
baseURL: 'https://shop.h888.fun/appapi/v1',
withCredentials: true,
timeout: 5000
baseURL: 'https://shop.h888.fun/appapi/v1',
withCredentials: true,
timeout: 5000
})
export const request = (url, method='GET', params={}, config={}) => {
export const request = (url, method = 'GET', params = {}, config = {}) => {
method = method.toUpperCase()
switch (method) {
case 'GET':
return ajax.get(url, {params, ...config})
case 'POST':
return ajax.post(url, params, config)
default:
return ajax.get(url, {params, ...config})
}
method = method.toUpperCase()
switch (method) {
case 'GET':
return ajax.get(url, { params, ...config })
case 'POST':
return ajax.post(url, params, config)
default:
return ajax.get(url, { params, ...config })
}
}
ajax.interceptors.request.use(
(config)=>{
if(config.requestBase=='sso'){
console.log('sso',import.meta.env.VITE_APP_SSO_URL)
(config) => {
if (config.requestBase == 'sso') {
console.log('sso', import.meta.env.VITE_APP_SSO_URL)
config.baseURL = import.meta.env.VITE_APP_SSO_URL
}
if(Cookies.get('token')){
if (Cookies.get('token')) {
config.headers.Authorization = Cookies.get('token')
}
if(Cookies.get('SessionId')){
if (Cookies.get('SessionId')) {
config.headers.SessionId = Cookies.get('SessionId')
}
return config
},
(error) =>{
(error) => {
return Promise.reject(error)
}
)
ajax.interceptors.response.use(
(response) => {
(response) => {
refreshToken(response)
return response.data
},
(error) => {
(error) => {
if (error.response) {
switch (error.response.status) {
case 401:
console.log('response 401')
Cookies.remove('token',{ expires: 30 ,domain: import.meta.env.VITE_APP_SSO_DOMAIN})
Cookies.remove('uid',{ expires: 30 ,domain: import.meta.env.VITE_APP_SSO_DOMAIN})
case 401:
console.log('response 401')
Cookies.remove('token', { expires: 30, domain: import.meta.env.VITE_APP_SSO_DOMAIN })
Cookies.remove('uid', { expires: 30, domain: import.meta.env.VITE_APP_SSO_DOMAIN })
router.replace({
path: '/login',
query: {redirect: router.currentRoute.fullPath}
})
router.replace({
path: '/login',
query: { redirect: router.currentRoute.fullPath }
})
}
}
if (error.code === 'ERR_NETWORK') {
return showToast('網路錯誤,請檢查是否上網')
}
return Promise.reject(error);
}
)
@ -68,6 +72,6 @@ ajax.interceptors.response.use(
function refreshToken(response) {
let token = response.headers.authorization
if (token) {
Cookies.set('token',res.data.token,{ expires: 30 ,domain: import.meta.env.VITE_APP_SSO_DOMAIN})
Cookies.set('token', res.data.token, { expires: 30, domain: import.meta.env.VITE_APP_SSO_DOMAIN })
}
}

Loading…
Cancel
Save