添加了html2pdf库,以及结算单管理接入接口
This commit is contained in:
parent
a69c3d1908
commit
79bd6b57dd
@ -44,6 +44,7 @@
|
||||
"element-ui": "^2.15.14",
|
||||
"file-saver": "1.3.8",
|
||||
"fuse.js": "3.4.4",
|
||||
"html2pdf.js": "^0.10.3",
|
||||
"js-beautify": "^1.10.2",
|
||||
"js-cookie": "2.2.0",
|
||||
"jsencrypt": "^3.0.0-rc.1",
|
||||
|
@ -9,4 +9,11 @@ export function getScenicValue (data) {
|
||||
})
|
||||
}
|
||||
|
||||
export default { getScenicValue }
|
||||
// 获取用户名称下拉
|
||||
export function getUserNameValue (userType) {
|
||||
return request({
|
||||
url: `api/dataDropdown/obtainUserListByType/${userType}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
export default { getScenicValue, getUserNameValue }
|
||||
|
@ -44,7 +44,13 @@ export function generateSettlementOrder(params) {
|
||||
}
|
||||
|
||||
// 获取生成结算单确认列表
|
||||
// export function get
|
||||
export function getGenerateSettleOrderConfirmList(params) {
|
||||
return request({
|
||||
url: '/api/settlementOrder/generateSettlementOrderConfirmList',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
// 更新结算单状态
|
||||
export function updateSettleOrderStatus(settlementOrderId, settlementOrderStatus) {
|
||||
@ -53,3 +59,11 @@ export function updateSettleOrderStatus(settlementOrderId, settlementOrderStatus
|
||||
method: 'put',
|
||||
})
|
||||
}
|
||||
|
||||
// 打印结算单数据
|
||||
export function printSettleOrderData(settlementOrderId) {
|
||||
return request({
|
||||
url: `api/settlementOrder/printSettlementOrder/${settlementOrderId}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
@ -39,4 +39,12 @@ export function allCustomer() {
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, enable, del, edit, allCustomer }
|
||||
// 查询单个客户信息
|
||||
export function getCustomerId(id) {
|
||||
return request({
|
||||
url: `aerocraftAdminApi/cnCustomer/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, enable, del, edit, allCustomer, getCustomerId }
|
||||
|
@ -517,7 +517,7 @@ export default {
|
||||
if (response) {
|
||||
// 确保有total字段
|
||||
if (response.total !== undefined) {
|
||||
this.page.total = response.total;
|
||||
this.page.total = Number(response.total);
|
||||
}
|
||||
// 确保records数组存在且是数组类型
|
||||
if (response && Array.isArray(response)) {
|
||||
|
@ -144,7 +144,7 @@ export default {
|
||||
this.getScenics();
|
||||
this.getPilots();
|
||||
this.getCustomers();
|
||||
this.getList();
|
||||
// this.getList();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -207,7 +207,7 @@ export default {
|
||||
id: record.id,
|
||||
};
|
||||
});
|
||||
this.page.total = response.total || 0;
|
||||
this.page.total = Number(response.total) || 0;
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
|
@ -8,12 +8,12 @@
|
||||
<div class="filter-container">
|
||||
<div class="filter-item">
|
||||
<span class="label">景区:</span>
|
||||
<el-select v-model="query.scenicArea" placeholder="请选择景区" clearable style="width: 200px;">
|
||||
<el-select v-model="query.attractionId" placeholder="请选择景区" clearable style="width: 200px;">
|
||||
<el-option
|
||||
v-for="item in scenicAreaOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
@ -56,19 +56,29 @@
|
||||
<el-table-column prop="customerName" label="客户名称" align="center" />
|
||||
<el-table-column prop="phoneNumber" label="手机号码" align="center" />
|
||||
<el-table-column prop="orderTime" label="下单时间" align="center" width="180" />
|
||||
<el-table-column prop="orderAmount" label="下单费用" align="center" />
|
||||
<el-table-column label="下单费用" width="180" align="center">
|
||||
<template slot-scope="scope">
|
||||
<div>基础费用:{{ scope.row.orderAmount.toFixed(2) }}</div>
|
||||
<div>附加费用:{{ scope.row.surchargeAmount.toFixed(4) }}</div>
|
||||
<div>总费用:{{ scope.row.totalAmount.toFixed(4) }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="scenicArea" label="景区" align="center" />
|
||||
<el-table-column prop="route" label="路线" align="center" />
|
||||
<el-table-column prop="initiator" label="订单发起人" align="center" />
|
||||
<el-table-column prop="orderType" label="订单类型" align="center" />
|
||||
<el-table-column prop="orderStatus" label="订单状态" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.orderStatus }}</span>
|
||||
<span :class="['status-text', scope.row.orderStatus === '已完成' ? 'success' : '']">
|
||||
{{ scope.row.orderStatus }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="settlementStatus" label="结算状态" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.settlementStatus }}</span>
|
||||
<span :class="['status-text', scope.row.settlementStatus === '已结算' ? 'success' : '']">
|
||||
{{ scope.row.settlementStatus }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -123,9 +133,26 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
先调用获取生成结算单确认列表接口,当点击确认生成时调用生成结算单接口
|
||||
-->
|
||||
<script>
|
||||
import { getOrderList, getGenerateSettleOrderConfirmList, generateSettlementOrder } from "@/api/order";
|
||||
import { allAreas } from "@/api/system/area";
|
||||
import { allScenic } from "@/api/system/scenic";
|
||||
import { allCustomer } from "@/api/system/customer";
|
||||
import { getList } from "@/api/system/pilot";
|
||||
import { getUser } from "@/api/system/user";
|
||||
import store from "@/store";
|
||||
|
||||
export default {
|
||||
name: 'generateOrder',
|
||||
created() {
|
||||
this.getScenics();
|
||||
this.getCustomers();
|
||||
this.getPilots();
|
||||
this.getList();
|
||||
},
|
||||
data() {
|
||||
const defaultStartDate = new Date('2015-10-02')
|
||||
const defaultEndDate = new Date('2015-10-10')
|
||||
@ -134,7 +161,8 @@ export default {
|
||||
settlementList: [],
|
||||
loading: false,
|
||||
query: {
|
||||
scenicArea: '',
|
||||
attractionId: undefined,
|
||||
customerId: undefined,
|
||||
dateRange: [defaultStartDate, defaultEndDate]
|
||||
},
|
||||
defaultDateRange: [defaultStartDate, defaultEndDate],
|
||||
@ -143,36 +171,134 @@ export default {
|
||||
size: 10,
|
||||
total: 0
|
||||
},
|
||||
scenicAreaOptions: [
|
||||
{ value: 'baiYunShan', label: '白云山' },
|
||||
{ value: 'huangShan', label: '黄山' },
|
||||
{ value: 'taiShan', label: '泰山' }
|
||||
],
|
||||
tableData: [
|
||||
{
|
||||
customerName: '小明',
|
||||
phoneNumber: '12345678',
|
||||
orderTime: '2024-01-01 00:00:00',
|
||||
orderAmount: '100.00',
|
||||
scenicArea: '白云山',
|
||||
route: 'a-b',
|
||||
initiator: '小红',
|
||||
orderType: '载物飞行',
|
||||
orderStatus: '已完成',
|
||||
settlementStatus: '未结算'
|
||||
}
|
||||
],
|
||||
scenicAreaOptions: [],
|
||||
customerOptions: [],
|
||||
pilotOptions: [],
|
||||
tableData: [],
|
||||
selection: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true;
|
||||
const params = {
|
||||
attractionId: this.query.attractionId,
|
||||
customerId: this.query.customerId,
|
||||
startTime: this.query.dateRange ? this.query.dateRange[0] : null,
|
||||
endTime: this.query.dateRange ? this.query.dateRange[1] : null,
|
||||
current: this.page.current,
|
||||
size: this.page.size,
|
||||
mainOrderStatus: 2, // 只查询已完成的订单
|
||||
settlementStatus: 0 // 只查询未结算的订单
|
||||
};
|
||||
getOrderList(params)
|
||||
.then((response) => {
|
||||
this.tableData = response.records.map((record) => {
|
||||
const customer = this.customerOptions.find(
|
||||
(c) => c.id === record.customerId
|
||||
);
|
||||
const scenic = this.scenicAreaOptions.find(s => s.id === record.attractionId);
|
||||
const initiator = this.pilotOptions.find(p => p.id === record.orderInitiatorId);
|
||||
return {
|
||||
id: record.id,
|
||||
customerName: customer ? customer.name : "未知客户",
|
||||
phoneNumber: record.customerPhone,
|
||||
orderTime: record.orderCreateTime,
|
||||
orderAmount: record.amount,
|
||||
totalAmount: record.totalAmount,
|
||||
surchargeAmount: record.surchargeAmount,
|
||||
scenicArea: scenic ? scenic.name : "未知景区",
|
||||
route: record.routeName,
|
||||
initiator: initiator ? initiator.name : "未知发起人",
|
||||
orderType: record.orderType === 1 ? "载物飞行" : "载人飞行",
|
||||
orderStatus: this.getOrderStatus(record.mainOrderStatus),
|
||||
settlementStatus: this.getSettlementStatus(record.settlementStatus),
|
||||
};
|
||||
});
|
||||
this.page.total = Number(response.total) || 0;
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
async getScenics() {
|
||||
try {
|
||||
let res = [];
|
||||
const userRes = await getUser({ id: store.getters.user.id });
|
||||
if (userRes && userRes.content && userRes.content.length > 0) {
|
||||
const userInfo = userRes.content[0];
|
||||
if (userInfo.roles && userInfo.roles.length > 0) {
|
||||
this.userRole = userInfo.roles[0].name;
|
||||
if (this.userRole === "区域负责人") {
|
||||
res = await allScenic({areaId: userInfo.areaId});
|
||||
} else if (this.userRole === "管理员" || this.userRole === "财务") {
|
||||
res = await allScenic();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res && Array.isArray(res)) {
|
||||
this.scenicAreaOptions = res.map((scenic) => ({
|
||||
id: scenic.id,
|
||||
name: scenic.name
|
||||
}));
|
||||
}
|
||||
this.getList();
|
||||
} catch (error) {
|
||||
console.error("获取景区列表失败:", error);
|
||||
}
|
||||
},
|
||||
|
||||
async getPilots() {
|
||||
try {
|
||||
const res = await getList();
|
||||
if (res) {
|
||||
this.pilotOptions = res.content.map((pilot) => ({
|
||||
id: pilot.id,
|
||||
name: pilot.name,
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取飞行员列表失败:", error);
|
||||
}
|
||||
},
|
||||
|
||||
async getCustomers() {
|
||||
try {
|
||||
const res = await allCustomer();
|
||||
if (res) {
|
||||
this.customerOptions = res.map((customer) => ({
|
||||
id: customer.id,
|
||||
name: customer.name,
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取客户列表失败:", error);
|
||||
}
|
||||
},
|
||||
|
||||
getOrderStatus(status) {
|
||||
const statusMap = {
|
||||
0: "未进行",
|
||||
1: "进行中",
|
||||
2: "已完成",
|
||||
3: "已取消"
|
||||
};
|
||||
return statusMap[status] || "未知状态";
|
||||
},
|
||||
|
||||
getSettlementStatus(status) {
|
||||
const statusMap = {
|
||||
0: "未结算",
|
||||
1: "结算中",
|
||||
2: "结算完成"
|
||||
};
|
||||
return statusMap[status] || "未知状态";
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
// 仅显示已完成且未结算的订单
|
||||
this.loading = true
|
||||
// 实际环境中应该调用API
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 500)
|
||||
this.page.current = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
handleSelectAll() {
|
||||
@ -182,14 +308,12 @@ export default {
|
||||
this.selection = val
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.page.size = val
|
||||
this.page.total = this.tableData.length // 更新总数
|
||||
// 重新加载数据
|
||||
this.page.size = val;
|
||||
this.getList();
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.page.current = val
|
||||
this.page.total = this.tableData.length // 更新总数
|
||||
// 重新加载数据
|
||||
this.page.current = val;
|
||||
this.getList();
|
||||
},
|
||||
handleDetail(row) {
|
||||
// 查看详情
|
||||
@ -221,14 +345,46 @@ export default {
|
||||
amount: '100元' // 示例数据,实际应根据订单计算
|
||||
}))
|
||||
|
||||
// 调用接口获取结算确认列表
|
||||
getGenerateSettleOrderConfirmList({
|
||||
orders: this.selection.map(order => order.id)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
// 成功获取结算确认列表
|
||||
this.settlementList = response.data || []
|
||||
} else {
|
||||
this.$message.error('获取结算确认列表失败: ' + response.message)
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('获取结算确认列表失败:', error)
|
||||
this.$message.error('获取结算确认列表失败,请稍后再试')
|
||||
})
|
||||
|
||||
// 显示确认弹窗
|
||||
this.dialogVisible = true
|
||||
},
|
||||
|
||||
handleConfirm() {
|
||||
// 调用生成结算单接口
|
||||
generateSettlementOrder({
|
||||
orders: this.selection.map(order => order.id)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
this.$message.success('结算单生成成功')
|
||||
this.dialogVisible = false
|
||||
this.$router.push('/order/orderDetail')
|
||||
} else {
|
||||
this.$message.error('结算单生成失败: ' + response.message)
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('生成结算单失败:', error)
|
||||
this.$message.error('生成结算单失败,请稍后再试')
|
||||
})
|
||||
this.dialogVisible = false
|
||||
// 跳转到订单详情页
|
||||
this.$router.push('/order/orderDetail')
|
||||
},
|
||||
|
||||
handleCancel() {
|
||||
@ -239,6 +395,13 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.status-text {
|
||||
color: #f56c6c;
|
||||
&.success {
|
||||
color: #67c23a;
|
||||
}
|
||||
}
|
||||
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
@ -28,16 +28,11 @@
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column prop="batchNo" label="订单批次号" align="left" />
|
||||
<el-table-column prop="status" label="结算状态" align="left">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.status }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="settlementTime" label="结算时间" width="180" align="left" />
|
||||
<el-table-column prop="operator" label="制单人" align="left" />
|
||||
<el-table-column prop="exportTime" label="导出时间" width="180" align="left" />
|
||||
<el-table-column prop="settlementStatus" label="结算状态" align="left">
|
||||
<el-table-column prop="batchNo" label="订单批次号" align="center" />
|
||||
<el-table-column prop="settlementTimeScope" label="结算时间" width="180" align="center" />
|
||||
<el-table-column prop="operator" label="制单人" align="center" />
|
||||
<el-table-column prop="updateTime" label="导出时间" width="180" align="center" />
|
||||
<el-table-column prop="settlementStatus" label="结算状态" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.settlementStatus }}</span>
|
||||
</template>
|
||||
@ -78,6 +73,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSettleOrderList } from '@/api/order'
|
||||
import { getUserNameValue } from '@/api/dropdown'
|
||||
|
||||
export default {
|
||||
name: 'settlementOrder',
|
||||
data() {
|
||||
@ -93,26 +91,65 @@ export default {
|
||||
},
|
||||
tableData: [
|
||||
{
|
||||
batchNo: 'JS123456789',
|
||||
status: '结算中',
|
||||
settlementTime: '2025-01-01 00:00:00',
|
||||
operator: '小明',
|
||||
exportTime: '2025-01-01 00:00:00',
|
||||
settlementStatus: '结算中'
|
||||
attractionId: 2,
|
||||
batchNo: "JS_2025072600008",
|
||||
createBy: "admin",
|
||||
createTime: "2025-07-26 14:42:38",
|
||||
operatorId: 1,
|
||||
settlementStatus: 2,
|
||||
settlementTimeScope: "2025-07-19 17:00:00~2025-07-19 17:00:00",
|
||||
updateBy: "admin",
|
||||
updateTime: "2025-07-26 14:42:38"
|
||||
},
|
||||
{
|
||||
batchNo: 'JS123456789',
|
||||
status: '待付款',
|
||||
settlementTime: '2025-01-01 00:00:00',
|
||||
operator: '小明',
|
||||
exportTime: '2025-01-01 00:00:00',
|
||||
settlementStatus: '已确认'
|
||||
}
|
||||
],
|
||||
selection: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
async fetchData() {
|
||||
this.loading = true
|
||||
try {
|
||||
const response = await getSettleOrderList(this.query)
|
||||
const operatorList = await getUserNameValue(0); // 只请求一次,避免每条都请求
|
||||
|
||||
const operatorMap = new Map();
|
||||
operatorList.forEach(item => {
|
||||
operatorMap.set(item.key, item.value);
|
||||
});
|
||||
response.records = response.records.map(record => ({
|
||||
...record,
|
||||
settlementStatus: this.getSettlementStatus(record.settlementStatus),
|
||||
operator: record.operatorId ? (operatorMap.get(record.operatorId) || '未知') : '未知',
|
||||
}))
|
||||
console.log('获取结算单列表:', response)
|
||||
this.tableData = response.records || []
|
||||
this.page.total = Number(response.total) || 0
|
||||
} catch (error) {
|
||||
console.error('获取结算单列表失败:', error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
getSettlementStatus(status) {
|
||||
const statusMap = {
|
||||
0: "结算中",
|
||||
1: "已确认",
|
||||
2: "结算完成",
|
||||
3: "已取消",
|
||||
};
|
||||
return statusMap[status] || "未知状态";
|
||||
},
|
||||
async getOperatorName(operatorId) {
|
||||
const response = await getUserNameValue(0);
|
||||
if (!response || response.length === 0) {
|
||||
return '未知';
|
||||
}
|
||||
const operatorName = response.find(item => item.key === operatorId);
|
||||
return operatorName.value || '未知';
|
||||
},
|
||||
handleSearch() {
|
||||
// 实现搜索逻辑
|
||||
console.log('搜索条件:', this.query)
|
||||
@ -131,6 +168,11 @@ export default {
|
||||
handleDetail(row) {
|
||||
// 查看详情
|
||||
console.log('查看详情:', row)
|
||||
// 跳转到订单详情页
|
||||
this.$router.push({
|
||||
path: '/order/orderDetail',
|
||||
query: { orderId: row.id.toString() }
|
||||
})
|
||||
},
|
||||
handlePrint(row) {
|
||||
// 打印结算单
|
||||
@ -151,7 +193,6 @@ export default {
|
||||
.filter-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
gap: 10px;
|
||||
|
||||
.filter-item {
|
||||
|
@ -13,6 +13,7 @@
|
||||
placeholder="请输入订单批次号"
|
||||
style="width: 200px"
|
||||
clearable
|
||||
@input="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
@ -22,6 +23,7 @@
|
||||
placeholder="请选择景区"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in scenicAreaOptions"
|
||||
@ -42,6 +44,7 @@
|
||||
:default-time="['00:00:00', '23:59:59']"
|
||||
:default-value="defaultDateRange"
|
||||
style="width: 350px"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -57,25 +60,38 @@
|
||||
<el-table
|
||||
ref="table"
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
:data="paginatedData"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="customerName" label="客户名称" align="center" />
|
||||
<el-table-column prop="phoneNumber" label="手机号码" align="center" />
|
||||
<el-table-column
|
||||
prop="orderTime"
|
||||
label="下单时间"
|
||||
align="center"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column prop="orderAmount" label="下单费用" align="center" />
|
||||
<el-table-column prop="scenicArea" label="景区" align="center" />
|
||||
<el-table-column prop="route" label="路线" align="center" />
|
||||
<el-table-column prop="initiator" label="订单发起人" align="center" />
|
||||
<el-table-column prop="orderType" label="订单类型" align="center" />
|
||||
<el-table-column prop="orderStatus" label="订单状态" align="center">
|
||||
<el-table-column prop="phone" label="手机号码" align="center" />
|
||||
<el-table-column prop="createTime" label="下单时间" align="center" width="180" />
|
||||
<el-table-column prop="totalAmount" label="下单费用" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.orderStatus }}</span>
|
||||
<span>{{ scope.row.totalAmount.toLocaleString('zh', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="scenicName" label="景区" align="center" />
|
||||
<el-table-column prop="routeIds" label="路线" align="center" />
|
||||
<el-table-column prop="createBy" label="订单发起人" align="center" />
|
||||
<el-table-column
|
||||
prop="orderType"
|
||||
label="订单类型"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.orderType === 1 ? '载物飞行' : '载人飞行' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="mainOrderStatus"
|
||||
label="订单状态"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span :class="getSettlementStatusClass(scope.row.mainOrderStatus)">
|
||||
{{ getOrderStatus(scope.row.mainOrderStatus) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@ -85,7 +101,7 @@
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span :class="getSettlementStatusClass(scope.row.settlementStatus)">
|
||||
{{ scope.row.settlementStatus }}
|
||||
{{ getSettlementStatusText(scope.row.settlementStatus) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -96,7 +112,7 @@
|
||||
:current-page.sync="page.current"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="page.size"
|
||||
:total="page.total"
|
||||
:total="tableData.length"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@ -107,31 +123,58 @@
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-buttons">
|
||||
<el-button
|
||||
v-if="settlementStatus === 0"
|
||||
type="primary"
|
||||
@click="handleCancelSettlement"
|
||||
:disabled="settlementStatus !== '结算中'"
|
||||
>
|
||||
取消结算
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handlePrint"> 打印结算单 </el-button>
|
||||
<el-button type="primary" @click="handlePrint">导出结算单</el-button>
|
||||
<el-button
|
||||
v-if="settlementStatus === 0"
|
||||
type="success"
|
||||
@click="handleStatusChange(1)"
|
||||
>
|
||||
确认结算
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="settlementStatus === 1"
|
||||
type="success"
|
||||
@click="handleStatusChange(2)"
|
||||
>
|
||||
完成结算
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- PDF导出组件 -->
|
||||
<settlement-pdf
|
||||
ref="settlementPdf"
|
||||
:order-data="currentOrder"
|
||||
v-show="false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSettleOrderDetail, updateSettleOrderStatus } from '@/api/order'
|
||||
import { getDetail } from "@/api/system/pilot";
|
||||
import { getCustomerId } from '@/api/system/customer'
|
||||
import { getScenicValue } from '@/api/dropdown'
|
||||
import SettlementPdf from './settlementPdf.vue'
|
||||
|
||||
export default {
|
||||
name: "orderDetail",
|
||||
components: {
|
||||
SettlementPdf
|
||||
},
|
||||
data() {
|
||||
const defaultStartDate = new Date("2015-10-02");
|
||||
const defaultEndDate = new Date("2015-10-10");
|
||||
const defaultStartDate = new Date();
|
||||
const defaultEndDate = new Date();
|
||||
return {
|
||||
loading: false,
|
||||
settlementStatus: "结算中", // 当前结算单状态
|
||||
scenicAreaOptions: [
|
||||
{ value: "baiYunShan", label: "白云山" },
|
||||
{ value: "huangShan", label: "黄山" },
|
||||
{ value: "taiShan", label: "泰山" },
|
||||
],
|
||||
scenicAreaOptions: [],
|
||||
settlementStatus: 0,
|
||||
currentOrder: null,
|
||||
query: {
|
||||
batchNo: "",
|
||||
scenicArea: "",
|
||||
@ -140,98 +183,152 @@ export default {
|
||||
defaultDateRange: [defaultStartDate, defaultEndDate],
|
||||
page: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 3,
|
||||
size: 10
|
||||
},
|
||||
tableData: [
|
||||
{
|
||||
customerName: "小明",
|
||||
phoneNumber: "12345678",
|
||||
orderTime: "2024-01-01 00:00:00",
|
||||
orderAmount: "100.00",
|
||||
scenicArea: "白云山",
|
||||
route: "a-b",
|
||||
initiator: "小红",
|
||||
orderType: "载物飞行",
|
||||
orderStatus: "已完成",
|
||||
settlementStatus: "未结算",
|
||||
},
|
||||
{
|
||||
customerName: "小明",
|
||||
phoneNumber: "12345678",
|
||||
orderTime: "2024-01-01 00:00:00",
|
||||
orderAmount: "100.00",
|
||||
scenicArea: "白云山",
|
||||
route: "a-b",
|
||||
initiator: "小红",
|
||||
orderType: "载物飞行",
|
||||
orderStatus: "进行中",
|
||||
settlementStatus: "结算中",
|
||||
},
|
||||
{
|
||||
customerName: "小明",
|
||||
phoneNumber: "12345678",
|
||||
orderTime: "2024-01-01 00:00:00",
|
||||
orderAmount: "100.00",
|
||||
scenicArea: "白云山",
|
||||
route: "a-b",
|
||||
initiator: "小红",
|
||||
orderType: "载物飞行",
|
||||
orderStatus: "已完成",
|
||||
settlementStatus: "结算完成",
|
||||
},
|
||||
],
|
||||
tableData: [],
|
||||
selection: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
paginatedData() {
|
||||
const start = (this.page.current - 1) * this.page.size
|
||||
const end = start + this.page.size
|
||||
return this.tableData.slice(start, end)
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
// 获取景区下拉数据
|
||||
const scenicResponse = await getScenicValue()
|
||||
this.scenicAreaOptions = scenicResponse.map(item => ({
|
||||
value: item.key,
|
||||
label: item.value
|
||||
}))
|
||||
|
||||
// 获取订单详情并处理数据
|
||||
const orderId = this.$route.query.orderId
|
||||
if (orderId) {
|
||||
this.loading = true
|
||||
try {
|
||||
const settleOrderDetail = await getSettleOrderDetail(orderId)
|
||||
await Promise.all(settleOrderDetail.map(async (item) => {
|
||||
// 获取客户名称
|
||||
const customerResponse = await getCustomerId(item.customerId)
|
||||
item.customerName = customerResponse.name
|
||||
|
||||
// 获取飞行员信息
|
||||
const pilotResponse = await getDetail(item.orderInitiatorId)
|
||||
item.createBy = pilotResponse.name
|
||||
|
||||
// 获取景区名称
|
||||
const scenic = scenicResponse.find(s => s.key === item.attractionId)
|
||||
item.scenicName = scenic ? scenic.value : ''
|
||||
}))
|
||||
this.tableData = settleOrderDetail
|
||||
if(settleOrderDetail.length > 0) {
|
||||
this.currentOrder = settleOrderDetail[0]
|
||||
this.settlementStatus = settleOrderDetail[0].settlementStatus
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching order details:', error)
|
||||
this.$message.error('获取订单详情失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSearch() {
|
||||
// 实现搜索逻辑
|
||||
console.log("搜索条件:", this.query);
|
||||
async handleSearch() {
|
||||
this.loading = true
|
||||
try {
|
||||
const params = {
|
||||
batchNo: this.query.batchNo,
|
||||
attractionId: this.query.scenicArea,
|
||||
startTime: this.query.dateRange ? this.query.dateRange[0] : null,
|
||||
endTime: this.query.dateRange ? this.query.dateRange[1] : null
|
||||
}
|
||||
const settleOrderDetail = await getSettleOrderDetail(params)
|
||||
await Promise.all(settleOrderDetail.map(async (item) => {
|
||||
const customerResponse = await getCustomerId(item.customerId)
|
||||
item.customerName = customerResponse.name
|
||||
const scenic = this.scenicAreaOptions.find(s => s.value === item.attractionId)
|
||||
item.scenicName = scenic ? scenic.label : ''
|
||||
}))
|
||||
this.tableData = settleOrderDetail
|
||||
// 重置分页到第一页
|
||||
this.page.current = 1
|
||||
} catch (error) {
|
||||
console.error('Error searching orders:', error)
|
||||
this.$message.error('搜索订单失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
getOrderStatus(status) {
|
||||
const statusMap = {
|
||||
0: "未进行",
|
||||
1: "进行中",
|
||||
2: "已完成",
|
||||
3: "已取消"
|
||||
};
|
||||
return statusMap[status] || "未知状态";
|
||||
},
|
||||
getSettlementStatusText(status) {
|
||||
const statusMap = {
|
||||
0: '结算中',
|
||||
1: '已确认',
|
||||
2: '结算完成',
|
||||
3: '已取消'
|
||||
};
|
||||
return statusMap[status] || '未知状态';
|
||||
},
|
||||
getSettlementStatusClass(status) {
|
||||
return {
|
||||
"status-red": ["未结算", "结算中"].includes(status),
|
||||
'status-red': [0, 3].includes(status),
|
||||
'status-green': status === 2,
|
||||
'status-orange': status === 1
|
||||
};
|
||||
},
|
||||
|
||||
handleCancelSettlement() {
|
||||
if (this.settlementStatus === "结算中") {
|
||||
// 更新所有订单的结算状态为未结算
|
||||
this.tableData.forEach((order) => {
|
||||
order.settlementStatus = "未结算";
|
||||
});
|
||||
this.settlementStatus = "未结算";
|
||||
this.$message.success("已取消结算");
|
||||
async handleCancelSettlement() {
|
||||
try {
|
||||
await updateSettleOrderStatus(this.$route.query.orderId, 3)
|
||||
this.settlementStatus = 3
|
||||
this.$message.success('取消结算成功')
|
||||
this.handleSearch() // 刷新数据
|
||||
} catch (error) {
|
||||
console.error('Error canceling settlement:', error)
|
||||
this.$message.error('取消结算失败')
|
||||
}
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.page.size = val;
|
||||
// 重新加载数据
|
||||
this.page.current = 1; // 重置到第一页
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.page.current = val;
|
||||
// 重新加载数据
|
||||
},
|
||||
handleDetail(row) {
|
||||
// 查看详情
|
||||
console.log("查看详情:", row);
|
||||
async handlePrint() {
|
||||
// 调用PDF组件的导出方法
|
||||
if (this.currentOrder) {
|
||||
try {
|
||||
await this.$refs.settlementPdf.generatePDF()
|
||||
} catch (error) {
|
||||
console.error('Error generating PDF:', error)
|
||||
this.$message.error('导出PDF失败')
|
||||
}
|
||||
} else {
|
||||
this.$message.warning('没有可导出的订单数据')
|
||||
}
|
||||
},
|
||||
handlePrint() {
|
||||
// 根据当前状态流转到下一个状态
|
||||
switch (this.settlementStatus) {
|
||||
case "结算中":
|
||||
this.settlementStatus = "已确认";
|
||||
this.$message.success("结算单状态已更新为:已确认");
|
||||
break;
|
||||
case "已确认":
|
||||
this.settlementStatus = "已完成";
|
||||
this.$message.success("结算单状态已更新为:已完成");
|
||||
break;
|
||||
case "已完成":
|
||||
// 执行打印逻辑
|
||||
console.log("打印结算单");
|
||||
break;
|
||||
async handleStatusChange(status) {
|
||||
try {
|
||||
await updateSettleOrderStatus(this.$route.query.orderId, status)
|
||||
this.settlementStatus = status
|
||||
const statusText = status === 1 ? '已确认' : '已完成'
|
||||
this.$message.success(`结算单状态已更新为:${statusText}`)
|
||||
this.handleSearch() // 刷新数据
|
||||
} catch (error) {
|
||||
console.error('Error updating settlement status:', error)
|
||||
this.$message.error('更新结算状态失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,26 +390,19 @@ export default {
|
||||
.status-red {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
// .pagination-container {
|
||||
// position: fixed;
|
||||
// bottom: 0;
|
||||
// left: 200px;
|
||||
// right: 0;
|
||||
// height: 60px;
|
||||
// background: white;
|
||||
// padding: 10px;
|
||||
// text-align: left;
|
||||
// box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.08);
|
||||
// z-index: 1000;
|
||||
// }
|
||||
|
||||
// .el-pagination {
|
||||
// padding: 10px 20px;
|
||||
// }
|
||||
.status-green {
|
||||
color: #67c23a;
|
||||
}
|
||||
.status-orange {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
margin-bottom: 70px;
|
||||
margin-top: 20px;
|
||||
::v-deep .el-table__body-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.el-button--text {
|
||||
@ -321,11 +411,4 @@ export default {
|
||||
color: #66b1ff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-table {
|
||||
margin-top: 20px;
|
||||
::v-deep .el-table__body-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
233
src/views/order/settlementOrder/orderDetail/settlementPdf.vue
Normal file
233
src/views/order/settlementOrder/orderDetail/settlementPdf.vue
Normal file
@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- PDF 可见区域 -->
|
||||
<div id="pdf-content" ref="pdfContent" style="width: 100%; margin: 0 auto; padding: 20px;">
|
||||
<h2 class="pdf-title">爱尚云收款结算单</h2>
|
||||
|
||||
<div class="info-row">
|
||||
<div class="info-item">
|
||||
<span class="label">结算单号:</span>
|
||||
<span class="value">{{ data.statementId }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">结算时间:</span>
|
||||
<span class="value">{{ data.date }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<div class="info-item">
|
||||
<span class="label">委托方:</span>
|
||||
<span class="value">{{ data.customer }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">数量:</span>
|
||||
<span class="value">{{ data.quantity }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<div class="info-item">
|
||||
<span class="label">金额(RMB):</span>
|
||||
<span class="value">{{ data.amount }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">大写:</span>
|
||||
<span class="value">{{ data.amountCN }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table border="1" cellspacing="0" cellpadding="5" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20%;">订单号</th>
|
||||
<th style="width: 25%;">执行时间</th>
|
||||
<th style="width: 15%;">重量</th>
|
||||
<th style="width: 20%;">金额</th>
|
||||
<th style="width: 20%;">确认人</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in data.items" :key="index">
|
||||
<td>{{ item.orderNo }}</td>
|
||||
<td>{{ item.execTime }}</td>
|
||||
<td>{{ item.weight }}</td>
|
||||
<td>{{ item.amount }}</td>
|
||||
<td>{{ item.confirmer }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import html2pdf from 'html2pdf.js'
|
||||
|
||||
export default {
|
||||
name: 'SettlementPdf',
|
||||
props: {
|
||||
orderData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: {
|
||||
statementId: '',
|
||||
date: '',
|
||||
customer: '',
|
||||
quantity: '',
|
||||
amount: '',
|
||||
amountCN: '',
|
||||
items: []
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
orderData: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.formatData(newVal)
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatData(orderData) {
|
||||
if (!orderData) {
|
||||
console.warn('No order data provided')
|
||||
return
|
||||
}
|
||||
console.log('Formatting order data:', orderData)
|
||||
// 格式化数据以适应PDF模板
|
||||
this.data = {
|
||||
statementId: orderData.orderNo || '',
|
||||
date: orderData.createTime || '',
|
||||
customer: orderData.customerName || '',
|
||||
quantity: orderData.cargoWeight ? `${orderData.cargoWeight}KG` : '0KG',
|
||||
amount: orderData.totalAmount ? `${orderData.totalAmount}元` : '0元',
|
||||
amountCN: this.convertToChinese(orderData.totalAmount || 0),
|
||||
items: [{
|
||||
orderNo: orderData.orderType === 1?'载物飞行':'载人飞行' || orderData.orderNo || '',
|
||||
execTime: orderData.orderFinishTime || '',
|
||||
weight: orderData.cargoWeight ? `${orderData.cargoWeight}KG` : '0KG',
|
||||
amount: orderData.totalAmount ? `${orderData.totalAmount}元` : '0元',
|
||||
confirmer: orderData.createBy || ''
|
||||
}]
|
||||
}
|
||||
},
|
||||
generatePDF() {
|
||||
const element = this.$refs.pdfContent
|
||||
const opt = {
|
||||
margin: 0.5,
|
||||
filename: `${this.data.statementId}.pdf`,
|
||||
image: { type: 'jpeg', quality: 0.98 },
|
||||
html2canvas: { scale: 2 },
|
||||
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' }
|
||||
}
|
||||
return html2pdf().set(opt).from(element).save()
|
||||
},
|
||||
convertToChinese(num) {
|
||||
const digitCN = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
|
||||
const unitCN = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿']
|
||||
let str = ''
|
||||
|
||||
// 处理整数部分
|
||||
const intNum = Math.floor(num)
|
||||
const intStr = intNum.toString()
|
||||
for (let i = 0; i < intStr.length; i++) {
|
||||
const digit = parseInt(intStr[i])
|
||||
str += digitCN[digit] + unitCN[intStr.length - 1 - i]
|
||||
}
|
||||
|
||||
// 处理小数部分
|
||||
const decimalNum = Math.round((num - intNum) * 100)
|
||||
if (decimalNum > 0) {
|
||||
str += '元'
|
||||
const decStr = decimalNum.toString().padStart(2, '0')
|
||||
if (decStr[0] !== '0') {
|
||||
str += digitCN[parseInt(decStr[0])] + '角'
|
||||
}
|
||||
if (decStr[1] !== '0') {
|
||||
str += digitCN[parseInt(decStr[1])] + '分'
|
||||
}
|
||||
} else {
|
||||
str += '元整'
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.pdf-title {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
font-family: SimSun, "宋体", serif;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 5px;
|
||||
line-height: 1.8;
|
||||
font-size: 20px;
|
||||
font-family: SimSun, "宋体", serif;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
flex: 0 0 45%;
|
||||
margin-bottom: 10px;
|
||||
/* display: flex;
|
||||
flex-wrap: wrap; */
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.info-item .label {
|
||||
white-space: nowrap;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.info-item .value {
|
||||
box-sizing: border-box;
|
||||
/* 增加下划线与字体距离 */
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 16px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin-top: 30px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
text-align: center;
|
||||
padding: 12px 8px;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 执行时间列的样式 */
|
||||
th:nth-child(2),
|
||||
td:nth-child(2) {
|
||||
font-family: Calibri, sans-serif;
|
||||
}
|
||||
|
||||
/* 重量列的样式 */
|
||||
td:nth-child(3) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#pdf-content {
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user