feat: 订单详情-待付款

feature/task1.0.0__0514__ch
向文可 4 years ago
parent 615e1fc04c
commit 26c96680d6

@ -1,64 +1,65 @@
{
"name": "msb-shop-admin",
"author": {
"name": "向文可",
"email": "1041367524@qq.com"
},
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "vite",
"build:test": "vite build --mode test",
"build:beta": "vite build --mode beta",
"build:prod": "vite build --mode prod",
"preview": "vite preview",
"prepare": "husky install",
"lint": "eslint src/**/*.{vue,js,jsx} --fix"
},
"dependencies": {
"@element-plus/icons": "^0.0.11",
"@vueup/vue-quill": "^1.0.0-beta.8",
"axios": "^0.26.1",
"dayjs": "^1.11.0",
"element-plus": "^2.1.7",
"lodash": "^4.17.21",
"qs": "^6.10.3",
"quill-image-uploader": "^1.2.2",
"sortablejs": "^1.14.0",
"vue": "^3.2.25",
"vue-router": "^4.0.14",
"vuex": "^4.0.2",
"vuex-persistedstate": "^4.1.0"
},
"devDependencies": {
"@commitlint/cli": "^13.2.1",
"@commitlint/config-conventional": "^13.2.0",
"@nabla/vite-plugin-eslint": "^1.4.0",
"@originjs/vite-plugin-global-style": "^1.0.2",
"@types/node": "^17.0.21",
"@vitejs/plugin-legacy": "^1.7.1",
"@vitejs/plugin-vue": "^2.2.0",
"@vitejs/plugin-vue-jsx": "^1.3.8",
"airbnb": "^0.0.2",
"consola": "^2.15.3",
"eslint": "^8.11.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0",
"husky": "^7.0.4",
"less": "^4.1.2",
"lint-staged": "^12.3.7",
"prettier": "^2.6.0",
"unplugin-auto-import": "^0.6.4",
"unplugin-vue-components": "^0.18.0",
"vite": "^2.8.0",
"vite-plugin-remove-console": "^0.0.6",
"vite-svg-loader": "^3.1.2"
},
"lint-staged": {
"src/**/*.{jsx,tsx,ts,js,vue}": [
"prettier --write",
"eslint --fix"
]
}
"name": "msb-shop-admin",
"author": {
"name": "向文可",
"email": "1041367524@qq.com"
},
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "vite",
"build:test": "vite build --mode test",
"build:beta": "vite build --mode beta",
"build:prod": "vite build --mode prod",
"preview": "vite preview",
"prepare": "husky install",
"lint": "eslint src/**/*.{vue,js,jsx} --fix"
},
"dependencies": {
"@element-plus/icons": "^0.0.11",
"@vueup/vue-quill": "^1.0.0-beta.8",
"axios": "^0.26.1",
"china-area-data": "^5.0.1",
"dayjs": "^1.11.0",
"element-plus": "^2.1.7",
"lodash": "^4.17.21",
"qs": "^6.10.3",
"quill-image-uploader": "^1.2.2",
"sortablejs": "^1.14.0",
"vue": "^3.2.25",
"vue-router": "^4.0.14",
"vuex": "^4.0.2",
"vuex-persistedstate": "^4.1.0"
},
"devDependencies": {
"@commitlint/cli": "^13.2.1",
"@commitlint/config-conventional": "^13.2.0",
"@nabla/vite-plugin-eslint": "^1.4.0",
"@originjs/vite-plugin-global-style": "^1.0.2",
"@types/node": "^17.0.21",
"@vitejs/plugin-legacy": "^1.7.1",
"@vitejs/plugin-vue": "^2.2.0",
"@vitejs/plugin-vue-jsx": "^1.3.8",
"airbnb": "^0.0.2",
"consola": "^2.15.3",
"eslint": "^8.11.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.5.0",
"husky": "^7.0.4",
"less": "^4.1.2",
"lint-staged": "^12.3.7",
"prettier": "^2.6.0",
"unplugin-auto-import": "^0.6.4",
"unplugin-vue-components": "^0.18.0",
"vite": "^2.8.0",
"vite-plugin-remove-console": "^0.0.6",
"vite-svg-loader": "^3.1.2"
},
"lint-staged": {
"src/**/*.{jsx,tsx,ts,js,vue}": [
"prettier --write",
"eslint --fix"
]
}
}

@ -0,0 +1,28 @@
<template>
<component :is="render" />
</template>
<script setup lang="jsx">
import data from 'china-area-data';
import ElCascader from './extra/ElCascader.vue';
const props = defineProps({
props: {
type: Object,
default: () => {
return {
expandTrigger: 'hover',
};
},
},
});
const attrs = useAttrs();
const slots = useSlots();
const convert = (obj) =>
obj
? Object.entries(obj).map((entry) => {
return { label: entry[1], value: entry[0], children: convert(data[entry[0]]) };
})
: [];
const options = convert(data[86]);
const render = () => <ElCascader {...{ ...props, options }} {...attrs} v-slots={slots} />;
</script>
<style lang="less" scoped></style>

@ -108,7 +108,7 @@
right: 0;
}
}
:deep(.el-image) {
.el-image {
width: v-bind(width);
height: v-bind(height);
}

@ -17,6 +17,18 @@ export default [
title: '订单管理',
icon: 'barcode-box-fill',
},
children: [
{
path: 'detail/:id',
name: 'OrderDetail',
component: () => import('@/views/sales/order/detail.vue'),
meta: {
title: '订单详情',
icon: 'barcode-box-fill',
hidden: true,
},
},
],
},
],
},

@ -89,6 +89,24 @@ const actions = {
}
return res;
},
address: async (context, data) => {
let res = await api.updateAddress(data);
if (res) {
ElMessage.success('修改收货人信息成功');
} else {
ElMessage.error('修改收货人信息失败');
}
return res;
},
fees: async (context, data) => {
let res = await api.updateFees(data);
if (res) {
ElMessage.success('修改费用信息成功');
} else {
ElMessage.error('修改费用信息失败');
}
return res;
},
save: async ({ dispatch }, data) => {
let save = data.id ? api.update : api.create;
let res = await save(data);

@ -0,0 +1,81 @@
<template>
<el-dialog v-model="state.visible" title="修改收货人信息">
<el-form ref="refsForm" v-loading="state.submitting" :model="state.form" :rules="state.rules">
<el-form-item label="收货人姓名" prop="recipientName">
<el-input v-model="state.form.recipientName" />
</el-form-item>
<el-form-item label="手机号码" prop="recipientPhone">
<el-input v-model="state.form.recipientPhone" />
</el-form-item>
<el-form-item label="所在区域" prop="area">
<el-area v-model="state.form.area" />
</el-form-item>
<el-form-item label="详细地址" prop="recipientAddress">
<el-input v-model="state.form.recipientAddress" type="textarea" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="close"></el-button>
<el-button :loading="state.submitting" type="primary" @click="handleSave"></el-button>
</template>
</el-dialog>
</template>
<script setup lang="jsx">
const store = useStore();
const refsForm = ref(null);
const state = reactive({
submitting: false,
visible: false,
order: null,
form: {
orderId: null,
area: [],
recipientName: null,
recipientPhone: null,
recipientAddress: null,
},
rules: {
orderId: [{ required: true, message: '订单ID不能为空' }],
area: [{ required: true, message: '省市区不能为空' }],
recipientName: [{ required: true, message: '收货人姓名不能为空' }],
recipientPhone: [{ required: true, message: '收货人手机不能为空' }],
recipientAddress: [{ required: true, message: '详细地址不能为空' }],
},
});
const show = (order) => {
state.order = order;
state.form = {
orderId: order.orderId,
area: [],
recipientName: order.logistics?.recipientName,
recipientPhone: order.logistics?.recipientPhone,
recipientAddress: order.logistics?.recipientAddress,
};
state.visible = true;
};
const close = () => {
state.visible = false;
};
defineExpose({
show,
close,
});
const handleSave = async () => {
state.submitting = true;
try {
await unref(refsForm).validate();
let res = await store.dispatch('order/address', state.form);
if (res) {
Object.assign(state.order, state.form);
state.visible = false;
}
} catch (e) {
console.info('取消关闭', e);
}
state.submitting = false;
};
</script>
<style lang="less" scoped></style>

@ -0,0 +1,217 @@
<template>
<div v-loading="state.loading" class="detail-container">
<el-steps :active="1" align-center>
<el-step v-for="(item, index) in state.steps" :key="index" :description="item.desc" :title="item.title" />
</el-steps>
<div class="card">
<div class="header">
<h3 class="left red">当前订单状态{{ state.form.payTypeDesc }}</h3>
<div class="right">
<el-button type="primary" @click="handleAddress"></el-button>
<el-button type="primary" @click="handleFees"></el-button>
<el-button type="danger" @click="handleClose"></el-button>
</div>
</div>
<el-scrollbar class="body">
<h3>基本信息</h3>
<el-table border :data="[state.form]">
<el-table-column align="center" header-align="center" label="订单编号" prop="orderNo" width="240" />
<el-table-column align="center" header-align="center" label="用户账号" prop="userId" width="240" />
<el-table-column
align="center"
header-align="center"
label="支付方式"
prop="payTypeDesc"
width="240"
/>
<el-table-column align="center" header-align="center" label="订单来源" prop="orderSourceDesc" />
<el-table-column align="center" header-align="center" label="订单类型" prop="quantity">
普通订单
</el-table-column>
</el-table>
<el-table border :data="[state.form]" style="margin-top: -1px">
<el-table-column
align="center"
header-align="center"
label="配送方式"
prop="logistics.companyName"
width="240"
/>
<el-table-column
align="center"
header-align="center"
label="物流单号"
prop="logistics.trackingNo"
width="240"
/>
<el-table-column align="center" header-align="center" label="自动确认收货时间" prop="receiveExpire">
<template #default="{ row }">{{ row.receiveExpire }}</template>
</el-table-column>
</el-table>
<br />
<h3>收货人信息</h3>
<el-table border :data="[state.form]">
<el-table-column
align="center"
header-align="center"
label="收货人"
prop="logistics.recipientName"
/>
<el-table-column
align="center"
header-align="center"
label="手机号码"
prop="logistics.recipientPhone"
/>
<el-table-column
align="center"
header-align="center"
label="收货地址"
prop="logistics.recipientAddress"
/>
</el-table>
<br />
<h3>商品信息</h3>
<el-table border :data="state.form.products">
<el-table-column align="center" header-align="center" label="商品图片" prop="productImageUrl">
<template #default="{ row }">
<el-image :alt="row.productName" height="64px" :src="row.productImageUrl" />
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="商品名称" prop="productName" />
<el-table-column align="center" header-align="center" label="价格" prop="realPrice">
<template #default="{ row }">{{ new Number(row.realPrice).toFixed(2) }}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="属性" prop="skuDescribe" />
<el-table-column align="center" header-align="center" label="数量" prop="quantity" />
<el-table-column align="center" header-align="center" label="小计" prop="realAmount">
<template #default="{ row }">{{ new Number(row.realAmount).toFixed(2) }}</template>
</el-table-column>
</el-table>
<h3 class="summary">
<span>合计</span>
<span class="red">200.00</span>
</h3>
<br />
<h3>费用信息</h3>
<el-table border :data="[state.form]">
<el-table-column align="center" header-align="center" label="商品合计" prop="totalAmount">
<template #default="{ row }">{{ new Number(row.totalAmount).toFixed(2) }}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="运费" prop="shippingAmount">
<template #default="{ row }">{{ new Number(row.shippingAmount).toFixed(2) }}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="活动优惠" prop="discountAmount">
<template #default="{ row }">-{{ new Number(row.discountAmount).toFixed(2) }}</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="应付款金额" prop="payAmount">
<template #default="{ row }">
<span class="red">{{ new Number(row.payAmount).toFixed(2) }}</span>
</template>
</el-table-column>
</el-table>
</el-scrollbar>
</div>
<CloseOrder ref="refsCloseOrder" />
<UpdateAddress ref="refsUpdateAddress" />
<UpdateFees ref="refsUpdateFees" />
</div>
</template>
<script setup lang="jsx">
import UpdateAddress from './address.vue';
import CloseOrder from './close.vue';
import UpdateFees from './fees.vue';
const store = useStore();
const route = useRoute();
const opts = computed(() => store.state.order.opts);
if (!unref(opts).init) {
store.dispatch('order/load');
}
const state = reactive({
steps: [
{
title: '提交订单',
desc: '',
},
{
title: '支付订单',
desc: '',
},
{
title: '平台发货',
desc: '',
},
{
title: '确认收货',
desc: '',
},
{
title: '完成评价',
desc: '',
},
],
loading: false,
form: {
products: [],
},
});
const handleLoad = async () => {
state.loading = true;
let res = await store.dispatch('order/detail', route.params.id);
if (res) {
Object.assign(state.form, res);
}
state.loading = false;
};
onActivated(handleLoad);
const refsCloseOrder = ref(null);
const handleClose = () => {
unref(refsCloseOrder).show(state.form.orderId);
};
const refsUpdateAddress = ref(null);
const handleAddress = () => {
unref(refsUpdateAddress).show(state.form);
};
const refsUpdateFees = ref(null);
const handleFees = () => {
unref(refsUpdateFees).show(state.form);
};
</script>
<style lang="less" scoped>
.detail-container {
display: flex;
flex-direction: column;
.card {
height: 100%;
flex-shrink: 1;
overflow: hidden;
margin-top: @layout-space;
display: flex;
flex-direction: column;
.header {
display: flex;
justify-content: space-between;
padding: @layout-space;
}
.body {
height: 100%;
flex-shrink: 1;
display: flex;
flex-direction: column;
padding: @layout-space;
h3 {
margin-bottom: @layout-space;
}
.summary {
text-align: right;
margin-top: @layout-space;
}
}
.red {
color: var(--el-color-danger);
}
}
}
</style>

@ -0,0 +1,72 @@
<template>
<el-dialog v-model="state.visible" title="修改费用信息">
<el-form ref="refsForm" v-loading="state.submitting" :model="state.form" :rules="state.rules">
<el-form-item label="商品合计" prop="totalAmount">{{ state.order.totalAmount }}</el-form-item>
<el-form-item label="运费" prop="shippingAmount">
<el-input-number v-model="state.form.shippingAmount" />
</el-form-item>
<el-form-item label="活动优惠" prop="discountAmount">{{ state.order.discountAmount }}</el-form-item>
<el-form-item label="应付款金额" prop="payAmount">
<span class="red">{{ state.order.payAmount }}</span>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="close"></el-button>
<el-button :loading="state.submitting" type="primary" @click="handleSave"></el-button>
</template>
</el-dialog>
</template>
<script setup lang="jsx">
const store = useStore();
const refsForm = ref(null);
const state = reactive({
submitting: false,
visible: false,
order: {},
form: {
orderId: null,
shippingAmount: 0,
},
rules: {
orderId: [{ required: true, message: '订单ID不能为空' }],
shippingAmount: [{ required: true, message: '运费不能为空' }],
},
});
const show = (order) => {
state.order = order;
state.form = {
orderId: order.orderId,
shippingAmount: order.shippingAmount,
};
state.visible = true;
};
const close = () => {
state.visible = false;
};
defineExpose({
show,
close,
});
const handleSave = async () => {
state.submitting = true;
try {
await unref(refsForm).validate();
let res = await store.dispatch('order/fees', state.form);
if (res) {
Object.assign(state.order, state.form);
state.visible = false;
}
} catch (e) {
console.info('取消关闭', e);
}
state.submitting = false;
};
</script>
<style lang="less" scoped>
.red {
color: var(--el-color-danger);
}
</style>

@ -141,7 +141,7 @@
router.push({
name: 'OrderDetail',
params: {
id: row.id,
id: row.orderId,
},
});
};

@ -20,7 +20,7 @@ export default (configEnv) => {
open: false,
proxy: {
'/api': {
target: 'http://192.168.10.20:8090/',
target: 'http://192.168.10.52:8090/',
// target: 'https://gateway-test.mashibing.cn', // 测试地址
// target: 'https://gateway.mashibing.cn', // 预发地址
// target: 'https://gateway.mashibing.com', // 生产环境

Loading…
Cancel
Save