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']

@ -31,7 +31,7 @@
<!-- Style css -->
<!-- <link rel="stylesheet" id="change-link" type="text/css" href="assets/css/style.css" /> -->
<title>UTel電商</title>
<title>Slash電商</title>
</head>
<body>
<div id="app"></div>

@ -15,17 +15,21 @@
<div class="address-wrap">
<!-- Address Star -->
<div class="address-box"
<div
class="address-box"
:class="{ active: ua.is_default }"
v-for="(ua, index) in userAddr"
:key="ua.address_id"
@click="handleSetDefault(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>
<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>
@ -34,12 +38,10 @@
<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 -->
@ -53,26 +55,43 @@
<!-- Footer End -->
<!-- Add New Address Off Canvas Start -->
<van-popup
v-model:show="showOffcanvas"
round
closeable
position="bottom"
>
<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-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"
@ -85,8 +104,13 @@
/>
</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
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" />
@ -94,10 +118,8 @@
</van-field>
</van-cell-group>
</div>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
新增
</van-button>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit"> 新增 </van-button>
</div>
</van-form>
</van-popup>
@ -105,117 +127,141 @@
</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 { getArea } from '@/services/shop'
import { getUserAddress,
addUserAddress,
delUserAddress,
setUserAddressDefault } from '@/services/user'
import { showToast } from "vant";
import "vant/es/toast/style";
const showPicker = ref(false)
import { getArea } from "@/services/shop";
import { getUserAddress, addUserAddress, delUserAddress, setUserAddressDefault } from "@/services/user";
const showOffcanvas = ref(false)
const route = useRoute();
const router = useRouter();
const orderStore = useOrderStore();
const fieldValue = ref('')
const showPicker = ref(false);
const userAddr = ref([])
const showOffcanvas = ref(false);
const columns = ref([])
const fieldValue = ref("");
const addrForm = ref()
const userAddr = 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
userAddr.value = addrRes.data;
}
let areaRes = await getArea()
let areaRes = await getArea();
if (areaRes.code === 200) {
columns.value = areaRes.data
columns.value = areaRes.data;
}
})
});
const onConfirm = ({ selectedOptions }) => {
showPicker.value = false;
let selectedArea = selectedOptions[0].text
let selectedArea = selectedOptions[0].text;
if (selectedOptions[1]) {
selectedArea += '-' + selectedOptions[1].text
selectedArea += "-" + selectedOptions[1].text;
}
if (selectedOptions[2]) {
selectedArea += '-' + selectedOptions[2].text
selectedArea += "-" + selectedOptions[2].text;
}
fieldValue.value = selectedArea
}
fieldValue.value = selectedArea;
};
const handleSubmit = () => {
// addrForm.value.submit()
}
};
const handleClose = () => {
addrForm.value.resetValidation()
}
addrForm.value.resetValidation();
};
const onSubmit = async () => {
let res = await addUserAddress(form.value)
let res = await addUserAddress(form.value);
showOffcanvas.value = false
showOffcanvas.value = false;
if (res.code === 200) {
userAddr.value = res.data
return showToast('新增成功')
userAddr.value = res.data;
return showToast("新增成功");
} else {
return showToast('新增失敗')
}
return showToast("新增失敗");
}
};
const handleDelete = async (id) => {
let res = await delUserAddress(id)
let res = await delUserAddress(id);
if (res.code === 200) {
userAddr.value = userAddr.value.filter((item) => {
if (item.address_id !== id) {
return item
return item;
}
})
showToast('刪除成功')
});
showToast("刪除成功");
} else {
showToast('刪除失敗')
}
showToast("刪除失敗");
}
};
const handleSetDefault = async (id) => {
let res = await setUserAddressDefault(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
item.is_default = true;
} else {
item.is_default = false
item.is_default = false;
}
return item
})
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>
@ -234,7 +280,6 @@ const handleSetDefault = async (id) => {
}
.heading-right {
}
}
</style>

@ -13,22 +13,19 @@
</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) {
@ -38,10 +35,7 @@ onMounted(async () => {
// }
// console.log('res',res.data.paymentUrl.web)
}
})
});
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

@ -3,7 +3,8 @@
<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 class="title-color font-md">
商品結帳
<span class="font-sm content-color">({{ cartStore.cartNum }} 樣商品)</span>
</h1>
</div>
@ -17,12 +18,8 @@
<!-- 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>訂單詳細</div>
<div></div>
</div>
<!-- Cart Item Section Start -->
<div class="cart-item-wrap pt-0">
@ -34,79 +31,126 @@
<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 class="plus-minus">X {{ item.goods_number }}</div>
</div>
</div>
</div>
</div>
<!-- Cart Item Section End -->
<!-- Address Section Start -->
<div class="address-block">
<div>
<div>
收貨人: wayne
</div>
<div>
收貨地址: 台北市
</div>
</div>
<div>
<van-button type="success" size="mini" @click="$router.replace('/address')"></van-button>
</div>
</div>
<!-- Address Section End -->
<!-- <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">
<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"
data-bs-target="#shipping" aria-expanded="false" aria-controls="shipping">
<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="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>
<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>
<!-- Shipping Option End -->
</template>
<div>
<van-button type="success" size="mini" @click="changeShipping"></van-button>
</div>
</div>
</div>
</div>
<!-- Accordion End -->
</div>
<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
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
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">
<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>
@ -128,9 +172,8 @@
<ul>
<li>
<span>金額</span>
<span>${{ detail.sum }}</span>
<span>${{ detail.sum_amount }}</span>
</li>
<li>
<span>折扣</span>
<span class="font-theme">-${{ detail.discount }}</span>
@ -139,15 +182,18 @@
<span>折價卷</span>
<a href="javascript:void(0);" class="font-danger">Apply Coupon</a>
</li> -->
<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 }}</span>
<span>{{ detail.shipping_fee }}</span>
</li>
<li>
<span>總金額</span>
<span>${{ detail.total }}</span>
<span>${{ detail.total_amount }}</span>
</li>
</ul>
<!-- Product Detail End -->
@ -160,100 +206,194 @@
<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: []
})
goods: [],
});
const paymentList = ref([]);
const paymentList = ref([])
const shippingList = ref([]);
const shippingList = ref([])
const logisticType = {
1: "711",
2: "全家",
3: "萊爾富",
4: "OK",
};
onMounted(async () => {
let res1 = await getPayments()
cartToOrder();
let res1 = await getPayments();
if (res1.code === 200) {
paymentList.value = res1.data
paymentList.value = res1.data;
}
let res2 = await getShippings()
let res2 = await getShippings();
if (res2.code === 200) {
shippingList.value = res2.data
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)
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()
cartStore.clearCart();
// window.location.href = res.data.info.paymentUrl.web
// console.log('resdata',res.data)
return router.replace({
name: 'Payment',
name: "Payment",
query: {
order_sn: res.data.order_sn,
pay_code: res.data.pay_code
}
})
}
return showToast('操作失敗')
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>
@ -264,7 +404,7 @@ const detail = computed(() => {
.delete-button {
i {
font-size: 20px;
color: #FFFFFF;
color: #ffffff;
}
}
@ -285,7 +425,6 @@ const detail = computed(() => {
div:nth-child(2) {
padding-right: 10px;
}
}
.price-color {
@ -299,7 +438,26 @@ const detail = computed(() => {
.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>

@ -11,8 +11,7 @@
<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 ref="formContainer" :style="{ display: showForm }"></div>
<div v-show="showTappay">
<form class="ui form">
<div class="field">
@ -20,40 +19,36 @@
<div id="tappay-iframe"></div>
</div>
</form>
<br>
<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,
@ -61,77 +56,85 @@ const config = {
isMaskCreditCardNumber: true,
maskCreditCardNumberRange: {
beginIndex: 6,
endIndex: 11
}
}
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 (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()
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
} 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)
break;
}
})
}
});
const onTapPay = () => {
TPDirect.card.getPrime(async (result) => {
if (result.status !== 0) {
alert('get prime error ' + result.msg)
return
alert("get prime error " + result.msg);
return;
}
console.log('get prime 成功prime: ' + result.card.prime)
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)
})
}
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;
font-family: Lato, "Helvetica Neue", Arial, Helvetica, sans-serif;
margin: 0;
outline: 0;
line-height: 1.21428571em;
padding: .578571em 1em;
padding: 0.578571em 1em;
font-size: 1em;
background: #fff;
border: 1px solid rgba(34,36,38,.15);
color: rgba(0,0,0,.87);
border-radius: .28571429rem;
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 .1s ease,border-color .1s ease;
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,7 +1,6 @@
<template>
<!-- Main Start -->
<main class="main-wrap login-page mb-xxl">
<!-- Login Section Start -->
<section class="login-section p-0">
<!-- Login Form Start -->
@ -17,13 +16,21 @@
<!-- Password Input start -->
<div class="input-box">
<input type="password" placeholder="登入密碼" required class="form-control" v-model="form.password"/>
<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>
<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 -->
@ -34,7 +41,8 @@
</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>
<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>
@ -46,48 +54,48 @@
</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)
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})
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>

@ -4,11 +4,13 @@
<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>
<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">Wayne</h2>
<h2 class="title-color">{{ form.real_name }}</h2>
</div>
</div>
</div>
@ -16,64 +18,47 @@
<!-- 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-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-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 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>

@ -10,22 +10,25 @@
<main class="main-wrap login-page mb-xxl">
<!-- <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>
<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.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>
<!-- Email Input End -->
<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">
@ -57,55 +60,51 @@
</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'))
let { id_token } = JSON.parse(sessionStorage.getItem("line"));
showLoadingToast({
duration: 0,
message: '資料傳送中...',
message: "資料傳送中...",
forbidClick: true,
});
let regRes = await register({token: id_token , ...form.value})
let regRes = await register({ token: id_token, ...form.value });
if (regRes.code === 500) {
showToast('line 登入已過期')
return router.push('/login')
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})
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')
return router.push("/user");
} else {
showToast('註冊失敗')
return router.push('/login')
}
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',

@ -8,3 +8,7 @@ export function addOrder(params) {
export function payment(params) {
return request('/payment/process', 'post', params)
}
export function setDefaultStoreId(store_id) {
return request('/shipping/setDefaultStoreId', 'post', { store_id })
}

@ -3,3 +3,19 @@ import { request } from '@/utils/request'
export function getShippings() {
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 })
}

@ -20,6 +20,10 @@ export function setUserAddressDefault(id) {
return request('/user/setUserAddressDefault', 'post', { id })
}
export function getUserDefaultAddress() {
return request('/user/getUserDefaultAddress', 'get')
}
export function getUserOrders() {
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,6 +1,7 @@
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',
@ -61,6 +62,9 @@ ajax.interceptors.response.use(
})
}
}
if (error.code === 'ERR_NETWORK') {
return showToast('網路錯誤,請檢查是否上網')
}
return Promise.reject(error);
}
)

Loading…
Cancel
Save