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

1002 lines
26 KiB

This file contains ambiguous Unicode characters!

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

<template>
<div class="main">
<!-- Breadcrumb: Start -->
<div class="breadcrumb-section">
<div>
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">電商管理中心</el-breadcrumb-item>
<el-breadcrumb-item><a href="/">訂單信息</a></el-breadcrumb-item>
</el-breadcrumb>
</div>
<div>
<el-button type="danger" size="small" @click="$router.push('/list')"></el-button>
</div>
</div>
<!-- Breadcrumb: End -->
<hr />
<el-card class="top-action">
<el-button type="primary" class="default-button-style" @click="handleGetOrder(orderInfo.prev)"
:disabled="!orderInfo.prev">前一個訂單</el-button>
<el-button type="primary" class="default-button-style" @click="handleGetOrder(orderInfo.next)"
:disabled="!orderInfo.next">後一個訂單</el-button>
<el-button type="primary" class="default-button-style" @click="handlePrint"></el-button>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>商品信息</span>
<!-- <el-button class="button" text>編輯</el-button> -->
</div>
</template>
<div class="card-body">
<el-table :data="orderInfo.goods_item" :summary-method="getSummaries" show-summary style="width: 100%">
<el-table-column prop="goods_name" label="商品名稱" />
<el-table-column prop="goods_sn" label="商品編號" />
<el-table-column prop="product_sn" label="貨品號" />
<el-table-column prop="goods_price" label="商品價格" />
<el-table-column prop="goods_number" label="購買數量" />
<el-table-column prop="goods_attr" label="屬性" />
<el-table-column prop="storage" label="庫存" />
<el-table-column prop="subtotal" label="小計" />
</el-table>
</div>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>基本信息</span>
<!-- <el-button class="button" text>編輯</el-button> -->
</div>
</template>
<div class="card-body">
<table>
<tr>
<td width="15%">
<div align="right"><strong>訂單號</strong></div>
</td>
<td width="35%">{{ orderInfo.order_sn }}</td>
<td width="15%">
<div align="right"><strong>訂單狀態</strong></div>
</td>
<td width="35%">
{{ orderInfo.order_status_name }},{{
orderInfo.pay_status_name
}},{{ orderInfo.shipping_status_name }}
</td>
</tr>
<tr>
<td>
<div align="right"><strong>購貨人</strong></div>
</td>
<td>
{{ orderInfo.consignee }}
<!-- [
<a href="" onclick="staticbar();return false;">顯示購貨人信息</a>
] -->
</td>
<td>
<div align="right"><strong>下單時間</strong></div>
</td>
<td>{{ orderInfo.add_time }}</td>
</tr>
<tr>
<td>
<div align="right"><strong>支付方式</strong></div>
</td>
<td>
{{ orderInfo.pay_name }}
<!-- <a
href="order.php?act=edit&order_id=645&step=payment"
class="special"
>編輯</a
>
(備註:
<span onclick="listTable.edit(this, 'edit_pay_note', 645)"
>N/A</span
>) -->
</td>
<td>
<div align="right"><strong>付款時間</strong></div>
</td>
<td>{{ orderInfo.pay_time }}</td>
</tr>
<tr>
<td>
<div align="right"><strong>配送方式</strong></div>
</td>
<td>
{{ orderInfo.shipping_name }}
</td>
<td>
<div align="right"><strong>發貨時間</strong></div>
</td>
<td>{{ orderInfo.shipping_time }}</td>
</tr>
<tr>
<td>
<div align="right"><strong>發貨單號</strong></div>
</td>
<td></td>
<!-- <td>
<div align="right"><strong>訂單來源</strong></div>
</td>
<td></td> -->
</tr>
</table>
</div>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>收貨人信息</span>
<!-- <el-button class="button" text>編輯</el-button> -->
</div>
</template>
<div class="card-body">
<template v-if="orderInfo.shipping_id === 2">
<table>
<tr>
<td width="15%">
<div align="right"><strong>超商類型:</strong></div>
</td>
<td colspan="3">{{ logisticType[orderInfo.address.type] }}</td>
</tr>
<tr>
<td width="15%">
<div align="right"><strong>超商名稱:</strong></div>
</td>
<td width="35%">{{ orderInfo.address.store_name }}</td>
<td width="15%">
<div align="right"><strong>超商代碼:</strong></div>
</td>
<td width="35%">{{ orderInfo.address.store_id }}</td>
</tr>
<tr>
<td width="15%">
<div align="right"><strong>超商電話:</strong></div>
</td>
<td width="35%">{{ orderInfo.address.store_tel }}</td>
<td width="15%">
<div align="right"><strong>超商地址:</strong></div>
</td>
<td width="35%">{{ orderInfo.address.store_address }}</td>
</tr>
<tr>
<td>
<div align="right"><strong>收貨人姓名:</strong></div>
</td>
<td>
{{ orderInfo.consignee }}
</td>
<td>
<div align="right"><strong>手機:</strong></div>
</td>
<td>
{{ orderInfo.mobile }}
</td>
</tr>
</table>
</template>
<template v-else>
<table>
<tr>
<td width="15%">
<div align="right"><strong>收貨人:</strong></div>
</td>
<td width="35%">{{ orderInfo.consignee }}</td>
<td width="15%">
<div align="right"><strong>電子郵件:</strong></div>
</td>
<td width="35%">{{ orderInfo.email }}</td>
</tr>
<tr>
<td>
<div align="right"><strong>地址:</strong></div>
</td>
<td>
{{
orderInfo.address.city +
orderInfo.address.district +
orderInfo.address.address
}}
</td>
<td>
<div align="right"><strong>電話:</strong></div>
</td>
<td>
{{ orderInfo.address.tel }}
</td>
</tr>
<!-- <tr>
<td>
<div align="right"><strong>標誌性建築:</strong></div>
</td>
<td></td>
<td>
<div align="right"><strong>最佳送貨時間:</strong></div>
</td>
<td></td>
</tr> -->
</table>
</template>
</div>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>其他信息</span>
<!-- <el-button class="button" text>編輯</el-button> -->
</div>
</template>
<div class="card-body">
<table>
<!-- <tr>
<td width="15%">
<div align="right"><strong>發票類型:</strong></div>
</td>
<td width="35%"></td>
<td width="15%">&nbsp;</td>
<td width="35%">&nbsp;</td>
</tr> -->
<!-- <tr>
<td>
<div align="right"><strong>發票抬頭:</strong></div>
</td>
<td></td>
<td>
<div align="right"><strong>發票內容:</strong></div>
</td>
<td></td>
</tr> -->
<tr>
<td>
<div><strong>客戶給商家的留言:</strong></div>
</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>
<div><strong>缺貨處理:</strong></div>
</td>
<td></td>
</tr>
<tr>
<td>
<div><strong>商家給客戶的留言:</strong></div>
</td>
<td></td>
</tr>
</table>
</div>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>費用信息</span>
<!-- <el-button class="button" text>編輯</el-button> -->
</div>
</template>
<div class="card-body">
<table>
<tr>
<td>
<div align="right">
<strong>
商品總金額NT${{ orderInfo.goods_amount }} - 折扣NT${{
orderInfo.discount
}}
+ 配送費用NT${{ orderInfo.shipping_fee }} + 支付費用NT${{
orderInfo.pay_fee
}}
</strong>
</div>
</td>
</tr>
<tr>
<td>
<div align="right">
<strong>
= 訂單總金額NT${{
parseInt(orderInfo.goods_amount) -
parseInt(orderInfo.discount) +
parseInt(orderInfo.shipping_fee) +
parseInt(orderInfo.pay_fee)
}}
</strong>
</div>
</td>
</tr>
<tr>
<td>
<div align="right">
<strong>
- 已付款金額NT$0 - 使用餘額: NT$0 - 使用積分: NT$0 -
使用紅包: NT$0
</strong>
</div>
</td>
</tr>
<tr>
<td>
<div align="right">
<strong>
= 應付款金額NT${{
parseInt(orderInfo.goods_amount) -
parseInt(orderInfo.discount) +
parseInt(orderInfo.shipping_fee) +
parseInt(orderInfo.pay_fee)
}}
</strong>
</div>
</td>
</tr>
</table>
</div>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>訂單操作</span>
</div>
</template>
<div class="card-body">
<table>
<tr>
<td width="25%">
<div align="right"><strong>操作備註:</strong></div>
</td>
<td width="75%">
<el-input v-model="orderInfo.action_note" :rows="2" type="textarea" />
</td>
</tr>
<tr>
<td>
<div align="right"><strong>當前可執行操作:</strong></div>
</td>
<td>
<el-button type="danger" v-for="(v, i) in orderInfo.op_list" :key="i" @click="handleOp(v)">{{ opName[v]
}}</el-button>
</td>
</tr>
</table>
</div>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>操作紀錄</span>
</div>
</template>
<div class="card-body">
<el-table :data="orderAction" style="width: 100%">
<el-table-column prop="action_user" label="操作者" />
<el-table-column prop="log_time" label="操作時間" />
<el-table-column prop="order_status" label="訂單狀態" />
<el-table-column prop="pay_status" label="付款狀態" />
<el-table-column prop="shipping_status" label="發貨狀態" />
<el-table-column prop="action_note" label="備註" />
</el-table>
</div>
</el-card>
</div>
<el-dialog v-model="dialogPrintCardVisible" @open="handleOpenPrintCard" title="配貨">
<div class="dialog-message">
{{ dialogMessage }}
</div>
<div>
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
<el-tab-pane label="正面" name="front" />
<el-tab-pane label="反面" name="back" />
</el-tabs>
<div id="printMe">
<div class="card-preview" v-show="showCardType === 0">
<img src="@/pages/order/images/front.png" />
<div class="front">
<!-- <img class="front-bg" src="@/assets/images/card/front.png"> -->
<div class="front-cname">{{ cardInfo.cname }}</div>
<div class="front-ename">{{ cardInfo.ename }}</div>
<img class="front-logo" :src="cardInfo.image || cardImg" />
</div>
</div>
<div class="card-preview" v-show="showCardType === 1">
<img src="@/pages/order/images/back.png" />
<div class="back">
<div class="nfcimg">
<qrcode-vue :value="cardInfo.nfcurl" :size="size" level="L" />
</div>
</div>
</div>
</div>
</div>
<div class="action">
<el-button type="primary" v-print="printObj">列印卡片</el-button>
<el-button type="primary" @click="printLabel">列印標籤</el-button>
<el-button type="primary" @click="handleNfcCard">複製Nfc網址</el-button>
<el-button type="primary" @click="makeNfcCard">製卡</el-button>
<el-button type="success" @click="handleFinish">完成</el-button>
</div>
</el-dialog>
<el-dialog v-model="dialogPrintVisible" @close="handleClosePrint" title="列印超商標籤">
<iframe id="printIframe" ref="printIframe" :src="printUrl" style="width: 340px; height: 520px" scrolling="no">
</iframe>
<el-button type="primary" v-print="'#printIframe'">列印</el-button>
</el-dialog>
<el-dialog v-model="dialogPrintAddrVisible" @close="handleClosePrintAddr" title="列印住址標籤">
<div id="printAddr">
<div class="addr">
<div class="address">
{{
orderInfo.address.city +
orderInfo.address.district +
orderInfo.address.address
}}
</div>
<div class="name">{{ orderInfo.address.consignee }}</div>
<div class="sender">匯康科技</div>
</div>
</div>
<el-button type="primary" v-print="'#printAddr'"></el-button>
</el-dialog>
</template>
<script setup>
import useClipboard from "vue-clipboard3";
import QrcodeVue from "qrcode.vue";
import { ref, reactive, onMounted, watch, computed, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import { getCardInfo, updateOrder } from "@/api/order";
import { getOrderInfo, getOrderAction, updateOrderAction } from "@/api/order";
import defaultImg from "@/assets/images/logo.png";
import { ElMessage } from "element-plus";
const route = useRoute();
const router = useRouter();
const order_id = route.query.order_id;
const logisticType = {
1: "711",
2: "全家",
3: "萊爾富",
4: "OK",
}
const opName = {
confirm: "確認",
pay: "付款",
unpay: "未付款",
prepare: "配貨",
ship: "發貨",
unship: "未發貨",
arrive: "已到達",
unarrive: "未到達",
receive: "收貨",
cancel: "取消",
invalid: "無效",
return: "退貨",
after_service: "售後",
remove: "移除",
finish: "完成",
};
const orderInfo = ref({
address: {},
});
const dialogMessage = ref("");
const orderAction = ref([]);
onMounted(async () => {
getOrder(order_id);
});
const cardImg = computed(() => {
return orderInfo.value.card_image || defaultImg;
});
const getOrder = async (order_id) => {
let promise1 = getOrderInfo(order_id);
let promise2 = getOrderAction(order_id);
let [res1, res2] = await Promise.all([promise1, promise2]);
if (res1.code == 200) {
orderInfo.value = res1.data;
orderInfo.value.address = JSON.parse(orderInfo.value.address);
if (orderInfo.value.shipping_id === 14) {
switch (orderInfo.value.address.type) {
case "1":
orderInfo.value.address.type = "711";
break;
case "2":
orderInfo.value.address.type = "全家";
break;
case "3":
orderInfo.value.address.type = "萊爾富";
break;
case "4":
orderInfo.value.address.type = "OK";
break;
}
}
}
if (res2.code == 200) {
orderAction.value = res2.data;
}
};
const handleGetOrder = (order_id) => {
if (!order_id || order_id === "null") return;
getOrder(order_id);
//不會rerender
router.push({ path: "/info", query: { order_id: order_id } });
};
const handlePrint = () => {
window.open(`order.php?act=info&order_id=${order_id}&print=1`);
};
const getSummaries = (param) => {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "合計";
return;
}
//index 在 1-6之間 不顯示
if (index > 0 && index < 7) {
sums[index] = "";
return;
}
const values = data.map((item) => Number(item[column.property]));
if (!values.every((value) => Number.isNaN(value))) {
sums[index] = `$ ${values.reduce((prev, curr) => {
const value = Number(curr);
if (!Number.isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0)}`;
} else {
sums[index] = "N/A";
}
});
return sums;
};
const dialogPrintCardVisible = ref(false);
const dialogPrintVisible = ref(false);
const dialogPrintAddrVisible = ref(false);
const handleOp = async (op) => {
console.log('op', op)
ElMessageBox.confirm("確認" + opName[op] + "?", "訂單操作", {})
.then(async () => {
let res = await updateOrderAction({
op,
order_id: orderInfo.value.order_id,
action_note: orderInfo.value.action_note,
});
if (res.code == 200) {
if (op === "remove") {
router.push({ path: "/list" });
} else {
getOrder(order_id);
}
}
})
.catch(() => {
return;
});
return;
};
const showCardType = ref(0);
const activeName = ref("front");
const cardInfo = ref({
cname: "",
ename: "",
images: "",
user_id: "",
});
const size = ref(300);
const handleOpenPrintCard = async () => {
changePrintPage("1022px 652px");
let res = await getCardInfo(orderInfo.value.order_sn);
if (res.code === 200) {
cardInfo.value = res.data;
}
};
const handleClick = (tab, event) => {
if (tab.props.name === "front") {
showCardType.value = 0;
} else {
showCardType.value = 1;
}
};
const printObj = ref({
id: "printMe",
popTitle: "card print",
beforeOpenCallback(vue) { },
clickMounted() {
size.value = 300;
},
openCallback(vue) {
// vue.printLoading = false;
size.value = 300;
},
closeCallback(vue) {
// size.value = 100;
},
});
const handleFinish = async () => {
let res = await updateOrderAction({
op: "printcard",
order_id: orderInfo.value.order_id,
action_note: '完成配貨',
});
if (res.code === 200) {
dialogPrintCardVisible.value = false;
getOrder(order_id);
}
};
//印標籤
const printUrl = ref("");
const printIframe = ref(null);
const printLabel = async () => {
switch (orderInfo.value.shipping_id) {
case 1:
changePrintPage("10cm 15cm landscape");
//列印住址標籤
dialogPrintAddrVisible.value = true;
break;
case 2:
if (orderInfo.value.address.type !== "2") {
let iWidth = 800; //視窗的寬度;
let iHeight = 600; //視窗的高度;
let iTop = (window.screen.availHeight - 30 - iHeight) / 2; //視窗的垂直位置;
let iLeft = (window.screen.availWidth - 10 - iWidth) / 2; //視窗的水平位置;
window.open(
`${import.meta.env.VITE_APP_BASE_URL}adminapi/v1/order/printlabel?order_id=${order_id}`,
"Print Label",
"height=" +
iHeight +
",,innerHeight=" +
iHeight +
",width=" +
iWidth +
",innerWidth=" +
iWidth +
",top=" +
iTop +
",left=" +
iLeft +
",status=no,location=no,status=no,menubar=no,toolbar=no,resizable=no,scrollbars=no"
);
} else {
changePrintPage("10cm 15cm");
//列印超商標籤
dialogPrintVisible.value = true;
printUrl.value = `${import.meta.env.VITE_APP_BASE_URL}adminapi/v1/order/printlabel?order_id=${order_id}`;
}
break;
}
return;
};
const handleClosePrint = () => {
changePrintPage("1022px 652px");
dialogPrintVisible.value = false;
};
const handleClosePrintAddr = () => {
changePrintPage("1022px 652px");
dialogPrintAddrVisible.value = false;
};
const changePrintPage = (page) => {
console.log("change pagesize");
var css = (css = `@page { size: ${page}; margin: 0; }`);
var head = document.head || document.getElementsByTagName("head")[0],
style = document.createElement("style");
style.media = "print";
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
};
const makeNfcCard = async () => {
let nfcReaderUrl = 'http://localhost:8088'
const data = new URLSearchParams();
//將cardInfo去除掉https://
let cardInfoUrl = cardInfo.value.nfcurl.replace('https://', '')
data.append('data', cardInfoUrl);
try {
let res = await fetch(nfcReaderUrl + '/writenfc', {
method: 'POST',
body: data,
})
res = await res.json()
if (res.code !== 200) {
dialogMessage.value = res.error
setTimeout(() => {
dialogMessage.value = ""
}, 3000);
return
}
dialogMessage.value = "製卡成功"
setTimeout(() => {
dialogMessage.value = ""
}, 3000);
return
} catch (e) {
dialogMessage.value = "請確認NFCCard程式是否開啟"
setTimeout(() => {
dialogMessage.value = ""
}, 3000);
}
}
const handleNfcCard = async () => {
const { toClipboard } = useClipboard();
try {
await toClipboard(cardInfo.value.nfcurl);
dialogMessage.value = "複製成功"
setTimeout(() => {
dialogMessage.value = ""
}, 2000);
return;
} catch (e) {
dialogMessage.value = "複製失敗"
setTimeout(() => {
dialogMessage.value = ""
}, 2000);
}
};
</script>
<style lang="less" scoped>
.top-action {
text-align: center;
}
.box-card {
margin-bottom: 10px;
}
.el-card {}
table {
width: 100%;
}
.nav {
display: flex;
.nav-item {
margin-right: 10px;
// border: 1px solid #666;
}
}
.card-preview {
width: 345px;
height: 220px;
// border: 1px solid #000;
margin: 0px;
position: relative;
img {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.front {
width: 100%;
height: 100%;
position: absolute;
.front-logo {
position: absolute;
width: 100px;
height: 100px;
top: 60px;
left: 20px;
}
.front-cname {
position: absolute;
top: 70px;
left: 180px;
font-size: 20px;
letter-spacing: 5px;
}
.front-ename {
position: absolute;
top: 110px;
left: 180px;
font-size: 12px;
letter-spacing: 5px;
}
}
.back {
width: 100%;
height: 100%;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
.nfcimg {
width: 100px;
height: 100px;
canvas {
width: 100px !important;
height: 100px !important;
}
}
}
}
#printAddr {
width: 600px;
height: 400px;
.addr {
.address {
font-size: 20px;
font-weight: bold;
line-height: 100px;
}
.name {
font-size: 20px;
font-weight: bold;
line-height: 100px;
padding-left: 100px;
}
.sender {
text-align: right;
font-size: 20px;
line-height: 100px;
}
}
}
@media print {
#printMe {
-webkit-print-color-adjust: exact !important;
color-adjust: exact !important;
}
.card-preview {
width: 1021px;
height: 651px;
// border: 1px solid #000;
margin: 0px;
position: relative;
img {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.front {
width: 100%;
height: 100%;
position: absolute;
.front-logo {
position: absolute;
width: 300px;
height: 300px;
top: 150px;
left: 80px;
}
.front-cname {
position: absolute;
top: 210px;
left: 530px;
font-size: 72px;
letter-spacing: 5px;
}
.front-ename {
position: absolute;
top: 320px;
left: 530px;
font-size: 40px;
letter-spacing: 7px;
}
}
.back {
width: 100%;
height: 100%;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
.nfcimg {
width: 300px;
height: 300px;
}
}
}
#printIframe {}
#printAddr {
width: 1020px;
height: 649px;
}
}
.action {
margin-top: 10px;
}
.message-override {
z-index: 9999 !important;
}
.dialog-message {
padding: 10px 5px;
margin-top: -40px;
margin-bottom: 10px;
color: #FF7575;
border: 1px solid #ccc;
}
</style>