车辆信息,备货单 等页面
This commit is contained in:
@@ -35,4 +35,75 @@ export class commonService {
|
||||
url: '/common/notice/unread'
|
||||
})
|
||||
}
|
||||
//货币下拉列表
|
||||
static getCurrencySelect() {
|
||||
return request.get<any>({
|
||||
url: '/common/preset/currency'
|
||||
})
|
||||
}
|
||||
|
||||
//国家下拉列表
|
||||
static getCountrySelect() {
|
||||
return request.get<any>({
|
||||
url: '/crm/customer/getCountry'
|
||||
})
|
||||
}
|
||||
//品牌下拉列表
|
||||
static getBrandSelect() {
|
||||
return request.get<any>({
|
||||
url: '/common/preset/brand'
|
||||
})
|
||||
}
|
||||
//车系下拉列表
|
||||
static getSeriesSelect(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/common/preset/brand/series',
|
||||
params
|
||||
})
|
||||
}
|
||||
//港口下拉列表
|
||||
static getPortSelect(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/common/preset/port',
|
||||
params
|
||||
})
|
||||
}
|
||||
//颜色下拉列表
|
||||
static getColorSelect(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/common/preset/color',
|
||||
params
|
||||
})
|
||||
}
|
||||
//改装下拉列表
|
||||
static getModificationSelect() {
|
||||
return request.get<any>({
|
||||
url: '/common/preset/modification'
|
||||
})
|
||||
}
|
||||
//字典下拉框
|
||||
static getDictSelect(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/dict/scope',
|
||||
params
|
||||
})
|
||||
}
|
||||
//字典分类下拉框
|
||||
static getDictTypeSelect() {
|
||||
return request.get<any>({
|
||||
url: '/admin/dict/group'
|
||||
})
|
||||
}
|
||||
//账户下拉框
|
||||
static getAccountSelect() {
|
||||
return request.get<any>({
|
||||
url: '/common/preset/account'
|
||||
})
|
||||
}
|
||||
//名下客户下拉框
|
||||
static getCustomerSelect() {
|
||||
return request.get<any>({
|
||||
url: '/crm/customer/preset'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,4 +207,19 @@ export class CrmService {
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
//备货单
|
||||
static getStockList(params: Api.Common.PaginatingParams) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/crm/stock/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
//添加备货单
|
||||
static addStock(params: any) {
|
||||
return request.post<Api.Work.AddResponse>({
|
||||
url: '/crm/stock/order/store',
|
||||
params
|
||||
// showErrorMessage: false // 不显示错误消息
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import request from '@/utils/http'
|
||||
|
||||
export class financeService {
|
||||
// 货币列表
|
||||
static getCurrencyList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/currency/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 货币添加
|
||||
static currencyAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/currency/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 货币详情
|
||||
static currencyDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/currency/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 货币编辑
|
||||
static currencyEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/currency/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 货币删除
|
||||
static currencyDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/currency/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 收款账户列表
|
||||
static getAccountList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/account/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 收款账户添加
|
||||
static accountAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/account/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 收款账户详情
|
||||
static accountDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/account/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 收款账户编辑
|
||||
static accountEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/account/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 收款账户删除
|
||||
static accountDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/account/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -245,4 +245,69 @@ export class systemService {
|
||||
params
|
||||
})
|
||||
}
|
||||
// 字典类型列表
|
||||
static getDictTypeList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/dict/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 字典类型新增/详情/编辑/删除
|
||||
static dictTypeAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/dict/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static dictTypeDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/dict/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static dictTypeEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/dict/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static dictTypeDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/dict/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 字典项列表
|
||||
static getDictItemList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/dict/item/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 字典项新增/详情/编辑/删除
|
||||
static dictItemAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/dict/item/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static dictItemDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/dict/item/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static dictItemEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/dict/item/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static dictItemDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/dict/item/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
import request from '@/utils/http'
|
||||
|
||||
export class vehicleService {
|
||||
// 车辆品牌列表
|
||||
static getBrandList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/brand/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 车辆品牌新增/详情/编辑/删除
|
||||
static brandAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/brand/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static brandDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/brand/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static brandEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/brand/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static brandDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/brand/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 车辆系列列表
|
||||
static getSeriesList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/brand/series/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 车辆系列新增/详情/编辑/删除
|
||||
static seriesAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/brand/series/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static seriesDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/brand/series/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static seriesEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/brand/series/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static seriesDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/brand/series/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 颜色管理
|
||||
static getColorList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/color/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
static colorAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/color/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static colorDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/color/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static colorEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/color/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static colorDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/color/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 改装管理
|
||||
static getModificationList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/modification/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
static modificationAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/modification/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static modificationDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/modification/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static modificationEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/modification/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static modificationDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/modification/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 港口管理
|
||||
static getPortList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/port/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
static portAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/port/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static portDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/port/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static portEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/port/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static portDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/port/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 车辆列表
|
||||
static getVehicleList(params: Api.Common.PaginatingParams & any) {
|
||||
return request.get<Api.Common.CommonListData>({
|
||||
url: '/admin/vehicle/sku/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
static vehicleAdd(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/vehicle/sku/store',
|
||||
params
|
||||
})
|
||||
}
|
||||
static vehicleDetail(params: any) {
|
||||
return request.get<any>({
|
||||
url: '/admin/vehicle/sku/show',
|
||||
params
|
||||
})
|
||||
}
|
||||
static vehicleEdit(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/vehicle/sku/update',
|
||||
params
|
||||
})
|
||||
}
|
||||
static vehicleDelete(params: any) {
|
||||
return request.post<Api.Common.AddResponse>({
|
||||
url: '/admin/vehicle/sku/destroy',
|
||||
params
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="选择客户"
|
||||
width="800px"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<div class="customer-selector">
|
||||
<!-- 搜索栏 -->
|
||||
<div class="search-bar">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入客户名称搜索"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
style="width: 300px"
|
||||
>
|
||||
<template #append>
|
||||
<el-button @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<!-- 客户列表 -->
|
||||
<el-table
|
||||
:data="customerList"
|
||||
v-loading="loading"
|
||||
height="400"
|
||||
@row-click="handleRowClick"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="contacts" label="客户名称" min-width="200" />
|
||||
<el-table-column prop="phone" label="联系电话" width="150" />
|
||||
<el-table-column prop="email" label="邮箱" width="200" />
|
||||
<el-table-column prop="country_name" label="国家" width="100" />
|
||||
<el-table-column prop="channel_name" label="客户来源" width="120" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm" :disabled="!selectedCustomer">
|
||||
确定
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
interface Customer {
|
||||
id: number | string
|
||||
contacts: string
|
||||
phone?: string
|
||||
email?: string
|
||||
country_name?: string
|
||||
channel_name?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
interface Props {
|
||||
visible: boolean
|
||||
keyword?: string
|
||||
page?: number
|
||||
pageSize?: number
|
||||
loading?: boolean
|
||||
data?: Customer[]
|
||||
total?: number
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:visible', value: boolean): void
|
||||
(e: 'search', keyword: string): void
|
||||
(e: 'page-change', page: number): void
|
||||
(e: 'size-change', size: number): void
|
||||
(e: 'select', customer: Customer): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
keyword: '',
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
loading: false,
|
||||
data: () => [],
|
||||
total: 0
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 响应式数据
|
||||
const searchKeyword = ref(props.keyword)
|
||||
const currentPage = ref(props.page)
|
||||
const selectedCustomer = ref<Customer | null>(null)
|
||||
|
||||
// 计算属性
|
||||
const dialogVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (value) => emit('update:visible', value)
|
||||
})
|
||||
|
||||
const customerList = computed(() => props.data)
|
||||
const loading = computed(() => props.loading)
|
||||
const total = computed(() => props.total)
|
||||
|
||||
// 监听外部数据变化
|
||||
watch(() => props.keyword, (newVal) => {
|
||||
searchKeyword.value = newVal
|
||||
})
|
||||
|
||||
watch(() => props.page, (newVal) => {
|
||||
currentPage.value = newVal
|
||||
})
|
||||
|
||||
// 方法
|
||||
const handleSearch = () => {
|
||||
emit('search', searchKeyword.value)
|
||||
}
|
||||
|
||||
const handleRowClick = (row: Customer) => {
|
||||
selectedCustomer.value = row
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
emit('size-change', size)
|
||||
}
|
||||
|
||||
const handleCurrentChange = (page: number) => {
|
||||
emit('page-change', page)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (selectedCustomer.value) {
|
||||
emit('select', selectedCustomer.value)
|
||||
handleClose()
|
||||
} else {
|
||||
ElMessage.warning('请先选择一个客户')
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
selectedCustomer.value = null
|
||||
dialogVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.customer-selector {
|
||||
.search-bar {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
:deep(.el-table__row) {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
&.current-row {
|
||||
background-color: #ecf5ff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="money-input">
|
||||
<el-input
|
||||
v-model="inputValue"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
type="number"
|
||||
:precision="precision"
|
||||
@input="handleInput"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #append>
|
||||
<el-select
|
||||
v-model="currencyValue"
|
||||
:placeholder="currencyPlaceholder"
|
||||
:disabled="disabled || readonly"
|
||||
style="width: 54px"
|
||||
@change="handleCurrencyChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in currencyOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
|
||||
interface CurrencyOption {
|
||||
value: string
|
||||
label: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
modelValue?: number
|
||||
currency?: string
|
||||
currencyOptions?: CurrencyOption[]
|
||||
placeholder?: string
|
||||
currencyPlaceholder?: string
|
||||
precision?: number
|
||||
disabled?: boolean
|
||||
readonly?: boolean
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: number | undefined): void
|
||||
(e: 'update:currency', value: string): void
|
||||
(e: 'change', value: number | undefined, currency: string): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: undefined,
|
||||
currency: '',
|
||||
currencyOptions: () => [],
|
||||
placeholder: '请输入金额',
|
||||
currencyPlaceholder: '币种',
|
||||
precision: 2,
|
||||
disabled: false,
|
||||
readonly: false
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 响应式数据
|
||||
const inputValue = ref<string>('')
|
||||
const currencyValue = ref<string>('')
|
||||
|
||||
// 计算属性
|
||||
const displayValue = computed(() => {
|
||||
if (props.modelValue === undefined || props.modelValue === null) return ''
|
||||
return String(props.modelValue)
|
||||
})
|
||||
|
||||
const displayCurrency = computed(() => {
|
||||
return props.currency || ''
|
||||
})
|
||||
|
||||
// 监听外部数据变化
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
if (newVal !== undefined && newVal !== null) {
|
||||
inputValue.value = String(newVal)
|
||||
} else {
|
||||
inputValue.value = ''
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => props.currency, (newVal) => {
|
||||
currencyValue.value = newVal || ''
|
||||
}, { immediate: true })
|
||||
|
||||
// 方法
|
||||
const handleInput = (value: string) => {
|
||||
const numValue = value === '' ? undefined : Number(value)
|
||||
emit('update:modelValue', numValue)
|
||||
}
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
const numValue = value === '' ? undefined : Number(value)
|
||||
emit('change', numValue, currencyValue.value)
|
||||
}
|
||||
|
||||
const handleCurrencyChange = (value: string) => {
|
||||
emit('update:currency', value)
|
||||
emit('change', props.modelValue, value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.money-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0;
|
||||
|
||||
.el-select {
|
||||
.el-input__wrapper {
|
||||
border-left: none;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,338 @@
|
||||
<template>
|
||||
<div class="order-item-row">
|
||||
<el-row :gutter="16">
|
||||
<!-- 车型选择 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="车型" required>
|
||||
<el-input
|
||||
v-model="item.model"
|
||||
placeholder="请选择车型"
|
||||
readonly
|
||||
@click="showVehicleDialog"
|
||||
>
|
||||
<template #append>
|
||||
<el-button @click="showVehicleDialog">选择</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 外观颜色 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="外观颜色">
|
||||
<el-select
|
||||
v-model="item.color_out"
|
||||
placeholder="请选择外观颜色"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="color in wcolorOptions"
|
||||
:key="color.value"
|
||||
:label="color.label"
|
||||
:value="color.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 内饰颜色 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="内饰颜色">
|
||||
<el-select
|
||||
v-model="item.color_in"
|
||||
placeholder="请选择内饰颜色"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="color in ncolorOptions"
|
||||
:key="color.value"
|
||||
:label="color.label"
|
||||
:value="color.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 改装 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="改装">
|
||||
<el-select
|
||||
v-model="item.modification"
|
||||
placeholder="请选择改装"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="mod in modificationOptions"
|
||||
:key="mod.value"
|
||||
:label="mod.label"
|
||||
:value="mod.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<!-- 改装费 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="改装费">
|
||||
<MoneyInput
|
||||
v-model:model-value="item.modification_fee"
|
||||
v-model:currency="item.modification_fee_currency"
|
||||
:currency-options="currencyOptions"
|
||||
placeholder="请输入改装费"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- FOB段运费 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="FOB段运费">
|
||||
<MoneyInput
|
||||
v-model:model-value="item.fob_freight"
|
||||
v-model:currency="item.fob_freight_currency"
|
||||
:currency-options="currencyOptions"
|
||||
placeholder="请输入FOB段运费"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 单价 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="单价">
|
||||
<MoneyInput
|
||||
v-model:model-value="item.unit_price"
|
||||
v-model:currency="item.unit_price_currency"
|
||||
:currency-options="currencyOptions"
|
||||
placeholder="请输入单价"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 总价 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="总价">
|
||||
<MoneyInput
|
||||
v-model:model-value="item.total_price"
|
||||
v-model:currency="item.total_price_currency"
|
||||
:currency-options="currencyOptions"
|
||||
placeholder="请输入总价"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<!-- 官方指导价 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="官方指导价">
|
||||
<MoneyInput
|
||||
v-model:model-value="item.guide_price"
|
||||
v-model:currency="item.guide_price_currency"
|
||||
:currency-options="currencyOptions"
|
||||
placeholder="请输入官方指导价"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 优惠 -->
|
||||
<el-col :span="6">
|
||||
<el-form-item label="优惠">
|
||||
<MoneyInput
|
||||
v-model:model-value="item.discount"
|
||||
v-model:currency="item.discount_currency"
|
||||
:currency-options="currencyOptions"
|
||||
placeholder="请输入优惠"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<el-col :span="12">
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" @click="handleCopy">复制</el-button>
|
||||
<el-button type="success" @click="handleAddAfter">新增</el-button>
|
||||
<el-button type="danger" @click="handleRemove">删除</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 车辆选择弹框 -->
|
||||
<VehicleSelectorDialog
|
||||
v-model:visible="vehicleDialog.visible"
|
||||
:keyword="vehicleDialog.keyword"
|
||||
:page="vehicleDialog.page"
|
||||
:page-size="vehicleDialog.pageSize"
|
||||
:loading="vehicleDialog.loading"
|
||||
:data="vehicleDialog.data"
|
||||
:total="vehicleDialog.total"
|
||||
@search="handleVehicleSearch"
|
||||
@page-change="handleVehiclePageChange"
|
||||
@size-change="handleVehicleSizeChange"
|
||||
@select="handleVehicleSelect"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import MoneyInput from './MoneyInput.vue'
|
||||
import VehicleSelectorDialog from './VehicleSelectorDialog.vue'
|
||||
|
||||
interface OrderItem {
|
||||
id?: string
|
||||
model: string
|
||||
color_out: string
|
||||
color_in: string
|
||||
modification: string
|
||||
modification_fee?: number
|
||||
modification_fee_currency?: string
|
||||
fob_freight?: number
|
||||
fob_freight_currency?: string
|
||||
unit_price?: number
|
||||
unit_price_currency?: string
|
||||
total_price?: number
|
||||
total_price_currency?: string
|
||||
guide_price?: number
|
||||
guide_price_currency?: string
|
||||
discount?: number
|
||||
discount_currency?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
interface ColorOption {
|
||||
value: string
|
||||
label: string
|
||||
}
|
||||
|
||||
interface ModificationOption {
|
||||
value: string
|
||||
label: string
|
||||
}
|
||||
|
||||
interface CurrencyOption {
|
||||
value: string
|
||||
label: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
item: OrderItem
|
||||
index: number
|
||||
wcolorOptions: ColorOption[]
|
||||
ncolorOptions: ColorOption[]
|
||||
modificationOptions: ModificationOption[]
|
||||
currencyOptions: CurrencyOption[]
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:item', item: OrderItem): void
|
||||
(e: 'copy', index: number): void
|
||||
(e: 'add-after', index: number): void
|
||||
(e: 'remove', index: number): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 车辆选择弹框状态
|
||||
const vehicleDialog = reactive({
|
||||
visible: false,
|
||||
keyword: '',
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
loading: false,
|
||||
data: [],
|
||||
total: 0,
|
||||
targetIndex: -1
|
||||
})
|
||||
|
||||
// 方法
|
||||
const showVehicleDialog = () => {
|
||||
vehicleDialog.targetIndex = props.index
|
||||
vehicleDialog.visible = true
|
||||
// 这里应该调用API获取车辆列表
|
||||
// 暂时使用模拟数据
|
||||
vehicleDialog.data = [
|
||||
{
|
||||
id: 1,
|
||||
model_name: 'Model S',
|
||||
brand_name: 'Tesla',
|
||||
series_name: 'S系列',
|
||||
msrp: 89990,
|
||||
currency: 'USD',
|
||||
color_exterior_text: '红色',
|
||||
color_interior_text: '黑色'
|
||||
}
|
||||
]
|
||||
vehicleDialog.total = 1
|
||||
}
|
||||
|
||||
const handleVehicleSearch = (keyword: string) => {
|
||||
vehicleDialog.keyword = keyword
|
||||
// 实现搜索逻辑
|
||||
}
|
||||
|
||||
const handleVehiclePageChange = (page: number) => {
|
||||
vehicleDialog.page = page
|
||||
// 实现分页逻辑
|
||||
}
|
||||
|
||||
const handleVehicleSizeChange = (size: number) => {
|
||||
vehicleDialog.pageSize = size
|
||||
// 实现分页大小改变逻辑
|
||||
}
|
||||
|
||||
const handleVehicleSelect = (vehicle: any) => {
|
||||
const idx = vehicleDialog.targetIndex
|
||||
if (idx >= 0) {
|
||||
// 回显车辆信息
|
||||
props.item.model = vehicle.model_name || vehicle.name || ''
|
||||
props.item.color_out = vehicle.color_exterior_text || ''
|
||||
props.item.color_in = vehicle.color_interior_text || ''
|
||||
props.item.guide_price = vehicle.msrp ?? props.item.guide_price
|
||||
if (vehicle.currency) {
|
||||
props.item.guide_price_currency = vehicle.currency
|
||||
}
|
||||
|
||||
emit('update:item', props.item)
|
||||
}
|
||||
vehicleDialog.visible = false
|
||||
}
|
||||
|
||||
const handleCopy = () => {
|
||||
emit('copy', props.index)
|
||||
}
|
||||
|
||||
const handleAddAfter = () => {
|
||||
emit('add-after', props.index)
|
||||
}
|
||||
|
||||
const handleRemove = () => {
|
||||
emit('remove', props.index)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.order-item-row {
|
||||
padding: 16px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fafafa;
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,205 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="选择车型"
|
||||
width="800px"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<div class="vehicle-selector">
|
||||
<!-- 搜索栏 -->
|
||||
<div class="search-bar">
|
||||
<el-input
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入车型名称搜索"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
style="width: 300px"
|
||||
>
|
||||
<template #append>
|
||||
<el-button @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<!-- 车辆列表 -->
|
||||
<el-table
|
||||
:data="vehicleList"
|
||||
v-loading="loading"
|
||||
height="400"
|
||||
@row-click="handleRowClick"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="model_name" label="车型名称" min-width="200" />
|
||||
<el-table-column prop="brand_name" label="品牌" width="120" />
|
||||
<el-table-column prop="series_name" label="车系" width="120" />
|
||||
<el-table-column prop="msrp" label="指导价" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ row.msrp ? `${row.msrp} ${row.currency || ''}` : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="color_exterior_text" label="外观颜色" width="100" />
|
||||
<el-table-column prop="color_interior_text" label="内饰颜色" width="100" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm" :disabled="!selectedVehicle">
|
||||
确定
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
interface Vehicle {
|
||||
id: number | string
|
||||
model_name: string
|
||||
brand_name: string
|
||||
series_name: string
|
||||
msrp?: number
|
||||
currency?: string
|
||||
color_exterior_text?: string
|
||||
color_interior_text?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
interface Props {
|
||||
visible: boolean
|
||||
keyword?: string
|
||||
page?: number
|
||||
pageSize?: number
|
||||
loading?: boolean
|
||||
data?: Vehicle[]
|
||||
total?: number
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:visible', value: boolean): void
|
||||
(e: 'search', keyword: string): void
|
||||
(e: 'page-change', page: number): void
|
||||
(e: 'size-change', size: number): void
|
||||
(e: 'select', vehicle: Vehicle): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
keyword: '',
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
loading: false,
|
||||
data: () => [],
|
||||
total: 0
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 响应式数据
|
||||
const searchKeyword = ref(props.keyword)
|
||||
const currentPage = ref(props.page)
|
||||
const selectedVehicle = ref<Vehicle | null>(null)
|
||||
|
||||
// 计算属性
|
||||
const dialogVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (value) => emit('update:visible', value)
|
||||
})
|
||||
|
||||
const vehicleList = computed(() => props.data)
|
||||
const loading = computed(() => props.loading)
|
||||
const total = computed(() => props.total)
|
||||
|
||||
// 监听外部数据变化
|
||||
watch(() => props.keyword, (newVal) => {
|
||||
searchKeyword.value = newVal
|
||||
})
|
||||
|
||||
watch(() => props.page, (newVal) => {
|
||||
currentPage.value = newVal
|
||||
})
|
||||
|
||||
// 方法
|
||||
const handleSearch = () => {
|
||||
emit('search', searchKeyword.value)
|
||||
}
|
||||
|
||||
const handleRowClick = (row: Vehicle) => {
|
||||
selectedVehicle.value = row
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
emit('size-change', size)
|
||||
}
|
||||
|
||||
const handleCurrentChange = (page: number) => {
|
||||
emit('page-change', page)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (selectedVehicle.value) {
|
||||
emit('select', selectedVehicle.value)
|
||||
handleClose()
|
||||
} else {
|
||||
ElMessage.warning('请先选择一个车型')
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
selectedVehicle.value = null
|
||||
dialogVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.vehicle-selector {
|
||||
.search-bar {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
:deep(.el-table__row) {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
&.current-row {
|
||||
background-color: #ecf5ff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,4 @@
|
||||
export { default as VehicleSelectorDialog } from './VehicleSelectorDialog.vue'
|
||||
export { default as CustomerSelectorDialog } from './CustomerSelectorDialog.vue'
|
||||
export { default as MoneyInput } from './MoneyInput.vue'
|
||||
export { default as OrderItemRow } from './OrderItemRow.vue'
|
||||
@@ -0,0 +1,358 @@
|
||||
<template>
|
||||
<div class="account-page">
|
||||
<div class="account-toolbar boxshadow">
|
||||
<div class="account-search-group">
|
||||
<el-form-item label="关键字:" label-width="70px">
|
||||
<el-input
|
||||
style="min-width: 180px"
|
||||
v-model="keyword"
|
||||
placeholder="请输入关键字"
|
||||
clearable
|
||||
@keyup.enter="getAccountList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getAccountList" v-ripple>搜索</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<ElRow>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton @click="showDialog('add')" v-ripple v-if="hasAuth('account@add')" type="primary"
|
||||
>新增账户</ElButton
|
||||
>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="账户名称" prop="account_name" min-width="160" />
|
||||
<ElTableColumn label="账户号码" prop="account_number" min-width="160" />
|
||||
<ElTableColumn label="银行名称" prop="bank_name" min-width="140" />
|
||||
<ElTableColumn label="开户支行" prop="bank_branch" min-width="160" />
|
||||
<ElTableColumn label="货币" prop="currency_id" min-width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ getCurrencyLabel(scope.row.currency_id) }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="排序" prop="sort" />
|
||||
<ElTableColumn label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'success' : 'info'">{{
|
||||
scope.row.status ? '启用' : '停用'
|
||||
}}</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="created_at" min-width="160" />
|
||||
<ElTableColumn fixed="right" label="操作" min-width="160px" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow>
|
||||
<el-button
|
||||
link
|
||||
@click="showDialog('edit', scope.row)"
|
||||
v-if="hasAuth('account@update')"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
@click="deleteAccount(scope.row)"
|
||||
v-if="hasAuth('account@destroy')"
|
||||
>删除</el-button
|
||||
>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增账户' : '编辑账户'"
|
||||
align-center
|
||||
width="700px"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="110px" class="form">
|
||||
<ElFormItem label="账户名称" prop="account_name">
|
||||
<ElInput v-model="form.account_name" placeholder="请输入账户名称" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="账户号码" prop="account_number">
|
||||
<ElInput v-model="form.account_number" placeholder="请输入账户号码" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="银行名称" prop="bank_name">
|
||||
<ElInput v-model="form.bank_name" placeholder="请输入银行名称" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="开户支行" prop="bank_branch">
|
||||
<ElInput v-model="form.bank_branch" placeholder="请输入开户支行" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="账户货币类型" prop="currency_id">
|
||||
<el-select v-model="form.currency_id" placeholder="请选择货币" style="width: 100%">
|
||||
<el-option
|
||||
v-for="opt in currencyOptions"
|
||||
:key="opt.id"
|
||||
:label="opt.currency_name + ' (' + opt.currency_code + ')'"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="form.sort" :min="0" :max="9999" style="width: 100%" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态">
|
||||
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="账户描述" prop="description">
|
||||
<ElInput
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="300"
|
||||
show-word-limit
|
||||
placeholder="请输入账户描述"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { financeService } from '@/api/financeApi'
|
||||
import { commonService } from '@/api/commonApi'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
defineOptions({ name: 'FinanceAccount' })
|
||||
|
||||
const loading = ref(false)
|
||||
const dialogVisible = ref(false)
|
||||
const dialogType = ref<'add' | 'edit'>('add')
|
||||
const formRef = ref<FormInstance>()
|
||||
const keyword = ref<string>('')
|
||||
const currencyFilter = ref<number | undefined>(undefined)
|
||||
const statusFilter = ref<number | undefined>(undefined)
|
||||
|
||||
// 下拉:货币
|
||||
const currencyOptions = ref<any[]>([])
|
||||
const loadCurrencyOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getCurrencySelect()
|
||||
currencyOptions.value = res || []
|
||||
} catch (e) {
|
||||
currencyOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const form = reactive<any>({
|
||||
id: '',
|
||||
currency_id: undefined,
|
||||
status: 1,
|
||||
sort: 0,
|
||||
bank_name: '',
|
||||
bank_branch: '',
|
||||
description: '',
|
||||
account_number: '',
|
||||
account_name: ''
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
currency_id: [{ required: true, message: '请选择账户货币类型', trigger: 'change' }],
|
||||
account_name: [{ required: true, message: '请输入账户名称', trigger: 'blur' }],
|
||||
account_number: [{ required: true, message: '请输入账户号码', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
})
|
||||
const tableData = ref<any[]>([])
|
||||
const tableRef = ref()
|
||||
|
||||
onMounted(() => {
|
||||
loadCurrencyOptions()
|
||||
getAccountList()
|
||||
})
|
||||
watch([keyword, currencyFilter, statusFilter], () => {
|
||||
pagination.currentPage = 1
|
||||
getAccountList()
|
||||
})
|
||||
|
||||
const getAccountList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = pagination
|
||||
const params = {
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: keyword.value
|
||||
}
|
||||
const { records, current, size, total } = await financeService.getAccountList(params)
|
||||
tableData.value = records || []
|
||||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (error) {
|
||||
console.error('获取账户列表失败:', error)
|
||||
ElMessage.error('获取账户列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getAccountList()
|
||||
}
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getAccountList()
|
||||
}
|
||||
|
||||
const showDialog = (type: 'add' | 'edit', row?: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
currency_id: row.currency_id,
|
||||
status: row.status,
|
||||
sort: row.sort ?? 0,
|
||||
bank_name: row.bank_name,
|
||||
bank_branch: row.bank_branch,
|
||||
description: row.description,
|
||||
account_number: row.account_number,
|
||||
account_name: row.account_name
|
||||
})
|
||||
} else {
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
currency_id: undefined,
|
||||
status: 1,
|
||||
sort: 0,
|
||||
bank_name: '',
|
||||
bank_branch: '',
|
||||
description: '',
|
||||
account_number: '',
|
||||
account_name: ''
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const deleteAccount = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该账户吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const { message } = await financeService.accountDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
getAccountList()
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
try {
|
||||
if (dialogType.value === 'add') {
|
||||
const { message } = await financeService.accountAdd({
|
||||
currency_id: form.currency_id,
|
||||
status: form.status,
|
||||
sort: form.sort,
|
||||
bank_name: form.bank_name,
|
||||
bank_branch: form.bank_branch,
|
||||
description: form.description,
|
||||
account_number: form.account_number,
|
||||
account_name: form.account_name
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const { message } = await financeService.accountEdit({
|
||||
id: form.id,
|
||||
currency_id: form.currency_id,
|
||||
status: form.status,
|
||||
sort: form.sort,
|
||||
bank_name: form.bank_name,
|
||||
bank_branch: form.bank_branch,
|
||||
description: form.description,
|
||||
account_number: form.account_number,
|
||||
account_name: form.account_name
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
getAccountList()
|
||||
} catch (error) {
|
||||
console.error('操作失败:', error)
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getCurrencyLabel = (id: number | undefined) => {
|
||||
if (!id) return '-'
|
||||
const found = currencyOptions.value.find((c: any) => c.id === id)
|
||||
return found ? `${found.currency_name} (${found.currency_code})` : id
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__empty-block) {
|
||||
height: 100% !important;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.account-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.account-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 20px 20px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.account-search-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.form {
|
||||
padding: 20px 0;
|
||||
}
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
.el-col2 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,389 @@
|
||||
<template>
|
||||
<div class="customer-page">
|
||||
<div class="customer-toolbar boxshadow">
|
||||
<div class="customer-search-group">
|
||||
<el-form-item label="关键字:" label-width="70px">
|
||||
<el-input style="min-width: 120px" v-model="keyword" placeholder="请输入关键字" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<ElRow>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton @click="showDialog('add')" v-ripple v-if="hasAuth('currency@add')"
|
||||
>新增</ElButton
|
||||
>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="货币编码" prop="currency_code" min-width="140" />
|
||||
<ElTableColumn label="货币名称" prop="currency_name" min-width="140" />
|
||||
<ElTableColumn label="符号" prop="currency_symbol" width="100" />
|
||||
<ElTableColumn label="当前汇率" prop="exchange_rate" min-width="120" />
|
||||
<ElTableColumn label="允许上浮动%" prop="float_percent_up" min-width="120" />
|
||||
<ElTableColumn label="允许下浮动%" prop="float_percent_down" min-width="120" />
|
||||
<ElTableColumn label="状态" prop="status" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'primary' : 'info'">
|
||||
{{ scope.row.status ? '启用' : '停用' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="created_at" min-width="160" />
|
||||
<ElTableColumn fixed="right" label="操作" width="240px">
|
||||
<template #default="scope">
|
||||
<ElRow>
|
||||
<el-button link @click="showDetail(scope.row)" v-if="hasAuth('currency@show')">
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
@click="showDialog('edit', scope.row)"
|
||||
v-if="hasAuth('currency@update')"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
@click="handleDelete(scope.row)"
|
||||
v-if="hasAuth('currency@destroy')"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增货币' : '编辑货币'"
|
||||
align-center
|
||||
width="640px"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px" class="form">
|
||||
<ElFormItem label="货币编码" prop="currency_code">
|
||||
<ElInput v-model="form.currency_code" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="货币名称" prop="currency_name">
|
||||
<ElInput v-model="form.currency_name" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="货币符号" prop="currency_symbol">
|
||||
<ElInput v-model="form.currency_symbol" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="当前汇率" prop="exchange_rate">
|
||||
<ElInputNumber
|
||||
v-model="form.exchange_rate"
|
||||
:min="0"
|
||||
:step="0.0001"
|
||||
:precision="6"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="允许上浮动%" prop="float_percent_up">
|
||||
<ElInputNumber
|
||||
v-model="form.float_percent_up"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="0.01"
|
||||
:precision="2"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="允许下浮动%" prop="float_percent_down">
|
||||
<ElInputNumber
|
||||
v-model="form.float_percent_down"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="0.01"
|
||||
:precision="2"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态">
|
||||
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<ElDialog v-model="detailVisible" title="货币详情" align-center width="640px">
|
||||
<div class="detail-dialog">
|
||||
<div class="section">
|
||||
<div class="info-grid">
|
||||
<div class="label">货币编码</div>
|
||||
<div class="value">{{ detailData.currency_code || '-' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">货币名称</div>
|
||||
<div class="value">{{ detailData.currency_name || '-' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">货币符号</div>
|
||||
<div class="value">{{ detailData.currency_symbol || '-' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">当前汇率</div>
|
||||
<div class="value">{{ detailData.exchange_rate ?? '-' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">允许上浮动%</div>
|
||||
<div class="value">{{ detailData.float_percent_up ?? '-' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">允许下浮动%</div>
|
||||
<div class="value">{{ detailData.float_percent_down ?? '-' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">状态</div>
|
||||
<div class="value">{{ detailData.status ? '启用' : '停用' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">创建时间</div>
|
||||
<div class="value">{{ detailData.created_at || '-' }}</div>
|
||||
</div>
|
||||
<div class="info-grid">
|
||||
<div class="label">更新时间</div>
|
||||
<div class="value">{{ detailData.updated_at || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="detailVisible = false">关闭</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { financeService } from '@/api/financeApi'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
const { hasAuth } = useAuth()
|
||||
defineOptions({ name: 'Type ' })
|
||||
const loading = ref(false)
|
||||
const dialogVisible = ref(false)
|
||||
const formRef = ref<FormInstance>()
|
||||
const keyword = ref<string>('')
|
||||
const rules = reactive<FormRules>({
|
||||
currency_code: [{ required: true, message: '请输入货币编码', trigger: 'blur' }],
|
||||
currency_name: [{ required: true, message: '请输入货币名称', trigger: 'blur' }],
|
||||
exchange_rate: [{ required: true, message: '请输入当前汇率', trigger: 'change' }]
|
||||
})
|
||||
const form = reactive<any>({
|
||||
id: '',
|
||||
currency_code: '',
|
||||
currency_name: '',
|
||||
currency_symbol: '',
|
||||
exchange_rate: 0,
|
||||
float_percent_up: 0,
|
||||
float_percent_down: 0,
|
||||
status: 1
|
||||
})
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
})
|
||||
// 表格数据
|
||||
const tableData = ref<any[]>([])
|
||||
// 表格实例引用
|
||||
const tableRef = ref()
|
||||
onMounted(() => {
|
||||
getCurrencyList()
|
||||
})
|
||||
watch([keyword], () => {
|
||||
pagination.currentPage = 1
|
||||
getCurrencyList()
|
||||
})
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getCurrencyList()
|
||||
}
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getCurrencyList()
|
||||
}
|
||||
// 获取货币列表
|
||||
const getCurrencyList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = pagination
|
||||
const { records, current, size, total } = await financeService.getCurrencyList({
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: keyword.value
|
||||
})
|
||||
tableData.value = records.map((item: any) => ({
|
||||
...item
|
||||
}))
|
||||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
const dialogType = ref('add')
|
||||
const detailVisible = ref(false)
|
||||
const detailData = ref<any>({})
|
||||
const showDialog = (type: 'add' | 'edit', row?: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
currency_code: row.currency_code,
|
||||
currency_name: row.currency_name,
|
||||
currency_symbol: row.currency_symbol,
|
||||
exchange_rate: row.exchange_rate ?? 0,
|
||||
float_percent_up: row.float_percent_up ?? 0,
|
||||
float_percent_down: row.float_percent_down ?? 0,
|
||||
status: row.status ?? 1
|
||||
})
|
||||
} else {
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
currency_code: '',
|
||||
currency_name: '',
|
||||
currency_symbol: '',
|
||||
exchange_rate: 0,
|
||||
float_percent_up: 0,
|
||||
float_percent_down: 0,
|
||||
status: 1
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleDelete = (row?: any) => {
|
||||
ElMessageBox.confirm('确定删除吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
const { message } = await financeService.currencyDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
getCurrencyList()
|
||||
})
|
||||
}
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (dialogType.value === 'add') {
|
||||
const { id, ...payload } = form
|
||||
const { message } = await financeService.currencyAdd(payload)
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const { message } = await financeService.currencyEdit(form)
|
||||
ElMessage.success(message)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
getCurrencyList()
|
||||
})
|
||||
}
|
||||
|
||||
const showDetail = async (row: any) => {
|
||||
detailVisible.value = true
|
||||
const res = await financeService.currencyDetail({ id: row.id })
|
||||
detailData.value = res || {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__empty-block) {
|
||||
height: 100% !important;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.customer-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.page-content {
|
||||
.svg-icon {
|
||||
width: 1.8em;
|
||||
height: 1.8em;
|
||||
overflow: hidden;
|
||||
vertical-align: -8px;
|
||||
fill: currentcolor;
|
||||
}
|
||||
}
|
||||
.customer-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 20px 20px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
|
||||
.customer-search-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
.message-text {
|
||||
padding: 10px 14px;
|
||||
line-height: 1.7;
|
||||
white-space: pre-line;
|
||||
word-break: break-word;
|
||||
}
|
||||
.detail-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
.section {
|
||||
background: var(--el-fill-color-blank);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 8px;
|
||||
padding: 12px 14px;
|
||||
}
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 96px 1fr;
|
||||
gap: 6px 12px;
|
||||
align-items: center;
|
||||
padding: 6px 0;
|
||||
}
|
||||
.label {
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
.value {
|
||||
color: var(--el-text-color-primary);
|
||||
font-size: 14px;
|
||||
}
|
||||
.content-box {
|
||||
background: var(--el-fill-color-lighter);
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
max-height: 320px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,524 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<div v-if="!isMobile" class="dict-layout">
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :xs="24" :sm="8" :lg="8">
|
||||
<div class="dict-type-card">
|
||||
<div class="card-header">
|
||||
<ElInput
|
||||
v-model="typeKeyword"
|
||||
placeholder="搜索类型名称/编码"
|
||||
clearable
|
||||
@keyup.enter="getTypeList"
|
||||
/>
|
||||
<ElButton style="margin-left: 8px" @click="getTypeList" v-ripple>搜索</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
style="margin-left: 8px"
|
||||
@click="showTypeDialog('add')"
|
||||
v-if="hasAuth('system@dictionary_add')"
|
||||
>新增类型</ElButton
|
||||
>
|
||||
</div>
|
||||
<el-table
|
||||
:data="typeTableData"
|
||||
v-loading="typeLoading"
|
||||
height="calc(100vh - 280px)"
|
||||
@row-click="handleTypeRowClick"
|
||||
:highlight-current-row="true"
|
||||
:row-key="'id'"
|
||||
>
|
||||
<el-table-column prop="dict_code" label="字典编码" />
|
||||
<el-table-column prop="dict_name" label="字典名称" />
|
||||
<el-table-column prop="category" label="字典分类" />
|
||||
<el-table-column prop="description" label="描述" show-overflow-tooltip />
|
||||
<el-table-column fixed="right" label="操作" min-width="140" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
size="small"
|
||||
@click.stop="showTypeDialog('edit', scope.row)"
|
||||
v-if="hasAuth('system@dictionary_update')"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
size="small"
|
||||
@click.stop="handleTypeDelete(scope.row)"
|
||||
v-if="hasAuth('system@dictionary_destroy')"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无类型" v-show="!typeLoading" />
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="type-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:current-page="typePagination.currentPage"
|
||||
:page-size="typePagination.pageSize"
|
||||
:total="typePagination.total"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
@current-change="handleTypeCurrentChange"
|
||||
@size-change="handleTypeSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="16" :lg="16">
|
||||
<div class="dict-item-card">
|
||||
<div class="card-header">
|
||||
<div class="left">
|
||||
<span v-if="activeType"
|
||||
>当前类型:{{ activeType.dict_name }}({{ activeType.dict_code }})</span
|
||||
>
|
||||
<span v-else class="muted">请选择左侧字典类型</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<ElInput
|
||||
v-model="itemKeyword"
|
||||
placeholder="搜索字典项名称/值"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="getItemList"
|
||||
/>
|
||||
<ElButton style="margin-left: 8px" @click="getItemList" v-ripple>搜索</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
style="margin-left: 8px"
|
||||
@click="showItemDialog('add')"
|
||||
:disabled="!activeType"
|
||||
v-if="hasAuth('system@dictionary_add')"
|
||||
>新增字典项</ElButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<ArtTable
|
||||
ref="itemTableRef"
|
||||
row-key="id"
|
||||
:loading="itemLoading"
|
||||
:data="itemTableData"
|
||||
:currentPage="itemPagination.currentPage"
|
||||
:pageSize="itemPagination.pageSize"
|
||||
:total="itemPagination.total"
|
||||
@size-change="handleItemSizeChange"
|
||||
@current-change="handleItemCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="ID" prop="id" width="80" />
|
||||
<ElTableColumn label="字典项名称" prop="item_label" min-width="160" />
|
||||
<ElTableColumn
|
||||
label="字典项值"
|
||||
prop="item_value"
|
||||
min-width="160"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<ElTableColumn label="备注" prop="remark" min-width="160" show-overflow-tooltip />
|
||||
<!-- <ElTableColumn label="排序" prop="sort" width="100" /> -->
|
||||
<ElTableColumn label="状态" prop="status" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'primary' : 'info'">{{
|
||||
scope.row.status ? '启用' : '禁用'
|
||||
}}</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="created_at" min-width="160" />
|
||||
<ElTableColumn fixed="right" label="操作" min-width="140px" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow>
|
||||
<el-button
|
||||
link
|
||||
@click="showItemDialog('edit', scope.row)"
|
||||
v-if="hasAuth('system@dictionary_update')"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
@click="handleItemDelete(scope.row)"
|
||||
v-if="hasAuth('system@dictionary_destroy')"
|
||||
>删除</el-button
|
||||
>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElDialog
|
||||
v-model="typeDialogVisible"
|
||||
:title="typeDialogType === 'add' ? '新增字典类型' : '编辑字典类型'"
|
||||
width="40%"
|
||||
align-center
|
||||
>
|
||||
<ElForm ref="typeFormRef" :model="typeForm" :rules="typeRules" label-width="100px">
|
||||
<ElFormItem label="字典分类" prop="category_id">
|
||||
<ElSelect v-model="typeForm.category_id" placeholder="请选择字典分类" clearable>
|
||||
<ElOption
|
||||
v-for="item in DictTypeSelect"
|
||||
:key="item.id"
|
||||
:label="item.item_label"
|
||||
:value="item.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="字典编码" prop="dict_code">
|
||||
<ElInput v-model="typeForm.dict_code" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="字典名称" prop="dict_name">
|
||||
<ElInput v-model="typeForm.dict_name" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="描述" prop="description">
|
||||
<ElInput v-model="typeForm.description" type="textarea" :rows="2" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态" prop="status">
|
||||
<ElSwitch v-model="typeForm.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="typeDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleTypeSubmit(typeFormRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<ElDialog
|
||||
v-model="itemDialogVisible"
|
||||
:title="itemDialogType === 'add' ? '新增字典项' : '编辑字典项'"
|
||||
width="50%"
|
||||
align-center
|
||||
>
|
||||
<ElForm ref="itemFormRef" :model="itemForm" :rules="itemRules" label-width="100px">
|
||||
<ElFormItem label="所属类型">
|
||||
<ElInput
|
||||
:model-value="activeType ? `${activeType.dict_name}(${activeType.dict_code})` : ''"
|
||||
disabled
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="字典项名称" prop="item_label">
|
||||
<ElInput v-model="itemForm.item_label" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="字典项值" prop="item_value">
|
||||
<ElInput v-model="itemForm.item_value" type="textarea" :rows="3" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="itemForm.sort" :min="0" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注" prop="remark">
|
||||
<ElInput v-model="itemForm.remark" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态" prop="status">
|
||||
<ElSwitch v-model="itemForm.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="itemDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleItemSubmit(itemFormRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
<div v-else class="mobile-hide-tip">
|
||||
<p>该页面暂不支持移动端访问</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { systemService } from '@/api/systemApi'
|
||||
import { commonService } from '@/api/commonApi'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
const { hasAuth } = useAuth()
|
||||
defineOptions({ name: 'Dictionary' })
|
||||
const { width } = useWindowSize()
|
||||
const isMobile = computed(() => width.value < 500)
|
||||
|
||||
// 左侧 类型
|
||||
const typeLoading = ref(false)
|
||||
const typeKeyword = ref<string>('')
|
||||
const typeTableData = ref<any[]>([])
|
||||
const typePagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
const activeType = ref<any | null>(null)
|
||||
|
||||
const typeFormRef = ref<FormInstance>()
|
||||
const typeDialogVisible = ref(false)
|
||||
const typeDialogType = ref<'add' | 'edit'>('add')
|
||||
const typeForm = reactive<any>({ id: '', code: '', name: '', status: 1 })
|
||||
const typeRules = reactive<FormRules>({
|
||||
dict_code: [{ required: true, message: '请输入字典编码', trigger: 'blur' }],
|
||||
dict_name: [{ required: true, message: '请输入字典名称', trigger: 'blur' }],
|
||||
category_id: [{ required: true, message: '请选择字典分类', trigger: 'blur' }]
|
||||
})
|
||||
const DictTypeSelect = ref<any[]>([])
|
||||
const getDictTypeSelect = async () => {
|
||||
const records = await commonService.getDictTypeSelect()
|
||||
DictTypeSelect.value = records.sysDictItem
|
||||
}
|
||||
|
||||
const getTypeList = async () => {
|
||||
typeLoading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = typePagination
|
||||
const { records, current, size, total } = await systemService.getDictTypeList({
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: typeKeyword.value
|
||||
})
|
||||
typeTableData.value = records
|
||||
Object.assign(typePagination, { currentPage: current, pageSize: size, total })
|
||||
if (!activeType.value && records && records.length) {
|
||||
activeType.value = records[0]
|
||||
await getItemList()
|
||||
}
|
||||
} finally {
|
||||
typeLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleTypeRowClick = async (row: any) => {
|
||||
activeType.value = row
|
||||
itemPagination.currentPage = 1
|
||||
await getItemList()
|
||||
}
|
||||
const handleTypeSizeChange = (val: number) => {
|
||||
typePagination.pageSize = val
|
||||
getTypeList()
|
||||
}
|
||||
const handleTypeCurrentChange = (val: number) => {
|
||||
typePagination.currentPage = val
|
||||
getTypeList()
|
||||
}
|
||||
|
||||
const showTypeDialog = (type: 'add' | 'edit', row?: any) => {
|
||||
getDictTypeSelect()
|
||||
typeDialogVisible.value = true
|
||||
typeDialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
Object.assign(typeForm, {
|
||||
id: row.id,
|
||||
dict_code: row.dict_code,
|
||||
dict_name: row.dict_name,
|
||||
description: row.description,
|
||||
category_id: row.category_id,
|
||||
status: row.status ?? 1
|
||||
})
|
||||
} else {
|
||||
Object.assign(typeForm, {
|
||||
id: '',
|
||||
dict_code: '',
|
||||
dict_name: '',
|
||||
description: '',
|
||||
status: 1,
|
||||
category_id: ''
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleTypeDelete = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该字典类型吗?删除后其字典项也可能被清理。', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
const { message } = await systemService.dictTypeDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
if (activeType.value && activeType.value.id === row.id) {
|
||||
activeType.value = null
|
||||
itemTableData.value = []
|
||||
itemPagination.total = 0
|
||||
}
|
||||
getTypeList()
|
||||
})
|
||||
}
|
||||
const handleTypeSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (typeDialogType.value === 'add') {
|
||||
const { message } = await systemService.dictTypeAdd({
|
||||
dict_code: typeForm.dict_code,
|
||||
dict_name: typeForm.dict_name,
|
||||
description: typeForm.description,
|
||||
status: typeForm.status
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const { message } = await systemService.dictTypeEdit({
|
||||
id: typeForm.id,
|
||||
dict_code: typeForm.dict_code,
|
||||
dict_name: typeForm.dict_name,
|
||||
description: typeForm.description,
|
||||
status: typeForm.status
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
typeDialogVisible.value = false
|
||||
getTypeList()
|
||||
})
|
||||
}
|
||||
|
||||
// 右侧 字典项
|
||||
const itemLoading = ref(false)
|
||||
const itemKeyword = ref<string>('')
|
||||
const itemTableData = ref<any[]>([])
|
||||
const itemTableRef = ref()
|
||||
const itemPagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
|
||||
const itemFormRef = ref<FormInstance>()
|
||||
const itemDialogVisible = ref(false)
|
||||
const itemDialogType = ref<'add' | 'edit'>('add')
|
||||
const itemForm = reactive<any>({
|
||||
id: '',
|
||||
item_label: '',
|
||||
item_value: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
remark: ''
|
||||
})
|
||||
const itemRules = reactive<FormRules>({
|
||||
item_label: [{ required: true, message: '请输入字典项', trigger: 'blur' }],
|
||||
item_value: [{ required: true, message: '请输入描述', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const getItemList = async () => {
|
||||
if (!activeType.value) return
|
||||
itemLoading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = itemPagination
|
||||
const { records, current, size, total } = await systemService.getDictItemList({
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: itemKeyword.value,
|
||||
id: activeType.value.id
|
||||
})
|
||||
itemTableData.value = records
|
||||
Object.assign(itemPagination, { currentPage: current, pageSize: size, total })
|
||||
} finally {
|
||||
itemLoading.value = false
|
||||
}
|
||||
}
|
||||
const handleItemSizeChange = (val: number) => {
|
||||
itemPagination.pageSize = val
|
||||
getItemList()
|
||||
}
|
||||
const handleItemCurrentChange = (val: number) => {
|
||||
itemPagination.currentPage = val
|
||||
getItemList()
|
||||
}
|
||||
const showItemDialog = (type: 'add' | 'edit', row?: any) => {
|
||||
itemDialogVisible.value = true
|
||||
itemDialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
Object.assign(itemForm, {
|
||||
id: row.id,
|
||||
item_label: row.item_label,
|
||||
item_value: row.item_value,
|
||||
sort: row.sort ?? 0,
|
||||
status: row.status ?? 1,
|
||||
remark: row.remark || ''
|
||||
})
|
||||
} else {
|
||||
Object.assign(itemForm, {
|
||||
id: '',
|
||||
item_label: '',
|
||||
item_value: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
remark: ''
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleItemDelete = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该字典项吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
const { message } = await systemService.dictItemDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
getItemList()
|
||||
})
|
||||
}
|
||||
const handleItemSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl || !activeType.value) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (itemDialogType.value === 'add') {
|
||||
const { message } = await systemService.dictItemAdd({
|
||||
dict_id: activeType.value.id,
|
||||
item_label: itemForm.item_label,
|
||||
item_value: itemForm.item_value,
|
||||
sort: itemForm.sort,
|
||||
status: itemForm.status,
|
||||
remark: itemForm.remark
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const { message } = await systemService.dictItemEdit({
|
||||
id: itemForm.id,
|
||||
dict_id: activeType.value.id,
|
||||
item_label: itemForm.item_label,
|
||||
item_value: itemForm.item_value,
|
||||
sort: itemForm.sort,
|
||||
status: itemForm.status,
|
||||
remark: itemForm.remark
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
itemDialogVisible.value = false
|
||||
getItemList()
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getTypeList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__empty-block) {
|
||||
height: 100% !important;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.dict-layout {
|
||||
.dict-type-card,
|
||||
.dict-item-card {
|
||||
background: var(--el-bg-color);
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
.left {
|
||||
font-weight: 500;
|
||||
}
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.muted {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
.type-pagination {
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,640 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<div v-if="!isMobile" class="dict-layout">
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :xs="24" :sm="10" :lg="10">
|
||||
<div class="dict-type-card">
|
||||
<div class="card-header">
|
||||
<div style="display: flex; align-items: center">
|
||||
<ElInput
|
||||
v-model="brandKeyword"
|
||||
placeholder="搜索品牌名称/编码"
|
||||
clearable
|
||||
@keyup.enter="getBrandList"
|
||||
/>
|
||||
<ElButton style="margin-left: 8px" @click="getBrandList" v-ripple>搜索</ElButton>
|
||||
</div>
|
||||
<ElButton
|
||||
type="primary"
|
||||
style="margin-left: 8px"
|
||||
@click="showBrandDialog('add')"
|
||||
v-if="hasAuth('brand@add')"
|
||||
>新增品牌</ElButton
|
||||
>
|
||||
</div>
|
||||
<el-table
|
||||
:data="brandTableData"
|
||||
v-loading="brandLoading"
|
||||
height="calc(100vh - 280px)"
|
||||
@row-click="handleBrandRowClick"
|
||||
:highlight-current-row="true"
|
||||
:row-key="'id'"
|
||||
>
|
||||
<el-table-column prop="brand_code" label="品牌编码" />
|
||||
<el-table-column prop="brand_name" label="品牌名称" />
|
||||
<el-table-column label="Logo" width="80">
|
||||
<template #default="scope">
|
||||
<div class="brand-logo-cell">
|
||||
<img
|
||||
v-if="scope.row.logo_full"
|
||||
:src="scope.row.logo_full"
|
||||
:alt="scope.row.brand_name"
|
||||
/>
|
||||
<div v-else class="logo-placeholder">{{ scope.row.brand_name?.charAt(0) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column prop="description" label="描述" show-overflow-tooltip /> -->
|
||||
<!-- <el-table-column prop="sort" label="排序" width="80" /> -->
|
||||
<el-table-column label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'success' : 'info'">
|
||||
{{ scope.row.status ? '启用' : '停用' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" label="操作" min-width="140" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
size="small"
|
||||
@click.stop="showBrandDialog('edit', scope.row)"
|
||||
v-if="hasAuth('brand@update')"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
size="small"
|
||||
@click.stop="handleBrandDelete(scope.row)"
|
||||
v-if="hasAuth('brand@destroy')"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无品牌" v-show="!brandLoading" />
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="type-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:current-page="brandPagination.currentPage"
|
||||
:page-size="brandPagination.pageSize"
|
||||
:total="brandPagination.total"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
@current-change="handleBrandCurrentChange"
|
||||
@size-change="handleBrandSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="14" :lg="14">
|
||||
<div class="dict-item-card">
|
||||
<div class="card-header">
|
||||
<div class="left">
|
||||
<span v-if="activeBrand"
|
||||
>当前品牌:{{ activeBrand.brand_name }}({{ activeBrand.brand_code }})</span
|
||||
>
|
||||
<span v-else class="muted">请选择左侧车辆品牌</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<ElInput
|
||||
v-model="seriesKeyword"
|
||||
placeholder="搜索系列名称/编码"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="getSeriesList"
|
||||
/>
|
||||
<ElButton style="margin-left: 8px" @click="getSeriesList" v-ripple>搜索</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
style="margin-left: 8px"
|
||||
@click="showSeriesDialog('add')"
|
||||
:disabled="!activeBrand"
|
||||
v-if="hasAuth('series@add')"
|
||||
>新增系列</ElButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<ArtTable
|
||||
ref="seriesTableRef"
|
||||
row-key="id"
|
||||
:loading="seriesLoading"
|
||||
:data="seriesTableData"
|
||||
:currentPage="seriesPagination.currentPage"
|
||||
:pageSize="seriesPagination.pageSize"
|
||||
:total="seriesPagination.total"
|
||||
@size-change="handleSeriesSizeChange"
|
||||
@current-change="handleSeriesCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="系列编码" prop="series_code" min-width="120" />
|
||||
<ElTableColumn label="系列名称" prop="series_name" min-width="140" />
|
||||
<ElTableColumn
|
||||
label="描述"
|
||||
prop="description"
|
||||
min-width="160"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<!-- <ElTableColumn label="排序" prop="sort" width="80" /> -->
|
||||
<ElTableColumn label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'success' : 'info'">{{
|
||||
scope.row.status ? '启用' : '停用'
|
||||
}}</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn fixed="right" label="操作" min-width="140px" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow>
|
||||
<el-button
|
||||
link
|
||||
@click="showSeriesDialog('edit', scope.row)"
|
||||
v-if="hasAuth('series@update')"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
@click="handleSeriesDelete(scope.row)"
|
||||
v-if="hasAuth('series@destroy')"
|
||||
>删除</el-button
|
||||
>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElDialog
|
||||
v-model="brandDialogVisible"
|
||||
:title="brandDialogType === 'add' ? '新增品牌' : '编辑品牌'"
|
||||
width="750px"
|
||||
align-center
|
||||
>
|
||||
<ElForm ref="brandFormRef" :model="brandForm" :rules="brandRules" label-width="100px">
|
||||
<ElFormItem label="品牌编码" prop="brand_code">
|
||||
<ElInput v-model="brandForm.brand_code" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="品牌名称" prop="brand_name">
|
||||
<ElInput v-model="brandForm.brand_name" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="品牌Logo" prop="logo">
|
||||
<ElUpload
|
||||
class="logo-uploader"
|
||||
:action="actionImageUplode"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
:on-success="handleLogoSuccess"
|
||||
:before-upload="beforeLogoUpload"
|
||||
accept="image/*"
|
||||
>
|
||||
<img v-if="brandForm.logo" :src="logourl" class="logo-preview" />
|
||||
<ElIcon v-else class="logo-uploader-icon"><Plus /></ElIcon>
|
||||
</ElUpload>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="品牌描述" prop="description">
|
||||
<ElInput v-model="brandForm.description" type="textarea" :rows="3" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="brandForm.sort" :min="0" :max="999" style="width: 100%" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态" prop="status">
|
||||
<ElSwitch v-model="brandForm.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="brandDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleBrandSubmit(brandFormRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<ElDialog
|
||||
v-model="seriesDialogVisible"
|
||||
:title="seriesDialogType === 'add' ? '新增系列' : '编辑系列'"
|
||||
width="750px"
|
||||
align-center
|
||||
>
|
||||
<ElForm ref="seriesFormRef" :model="seriesForm" :rules="seriesRules" label-width="100px">
|
||||
<ElFormItem label="所属品牌">
|
||||
<ElInput
|
||||
:model-value="
|
||||
activeBrand ? `${activeBrand.brand_name}(${activeBrand.brand_code})` : ''
|
||||
"
|
||||
disabled
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="系列编码" prop="series_code">
|
||||
<!-- <ElInput v-model="seriesForm.series_code" :disabled="seriesDialogType === 'edit'" /> -->
|
||||
<ElInput v-model="seriesForm.series_code" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="系列名称" prop="series_name">
|
||||
<ElInput v-model="seriesForm.series_name" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="系列描述" prop="description">
|
||||
<ElInput v-model="seriesForm.description" type="textarea" :rows="3" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="seriesForm.sort" :min="0" :max="999" style="width: 100%" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态" prop="status">
|
||||
<ElSwitch v-model="seriesForm.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="seriesDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSeriesSubmit(seriesFormRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
<div v-else class="mobile-hide-tip">
|
||||
<p>该页面暂不支持移动端访问</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { vehicleService } from '@/api/vehicleApi'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { useUploadHeaders } from '@/composables/useUploadHeaders'
|
||||
const { uploadHeaders } = useUploadHeaders()
|
||||
let actionImageUplode = `${import.meta.env.VITE_API_URL}/ticket/upload`
|
||||
const { hasAuth } = useAuth()
|
||||
defineOptions({ name: 'VehicleBrand' })
|
||||
const { width } = useWindowSize()
|
||||
const isMobile = computed(() => width.value < 500)
|
||||
const logourl = ref('')
|
||||
// 左侧 品牌
|
||||
const brandLoading = ref(false)
|
||||
const brandKeyword = ref<string>('')
|
||||
const brandTableData = ref<any[]>([])
|
||||
const brandPagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
const activeBrand = ref<any | null>(null)
|
||||
|
||||
const brandFormRef = ref<FormInstance>()
|
||||
const brandDialogVisible = ref(false)
|
||||
const brandDialogType = ref<'add' | 'edit'>('add')
|
||||
const brandForm = reactive<any>({
|
||||
id: '',
|
||||
brand_code: '',
|
||||
brand_name: '',
|
||||
logo: '',
|
||||
description: '',
|
||||
sort: 0,
|
||||
status: 1
|
||||
})
|
||||
const brandRules = reactive<FormRules>({
|
||||
brand_code: [{ required: true, message: '请输入品牌编码', trigger: 'blur' }],
|
||||
brand_name: [{ required: true, message: '请输入品牌名称', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const getBrandList = async () => {
|
||||
brandLoading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = brandPagination
|
||||
const { records, current, size, total } = await vehicleService.getBrandList({
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: brandKeyword.value
|
||||
})
|
||||
brandTableData.value = records
|
||||
Object.assign(brandPagination, { currentPage: current, pageSize: size, total })
|
||||
if (!activeBrand.value && records && records.length) {
|
||||
activeBrand.value = records[0]
|
||||
await getSeriesList()
|
||||
}
|
||||
} finally {
|
||||
brandLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleBrandRowClick = async (row: any) => {
|
||||
activeBrand.value = row
|
||||
seriesPagination.currentPage = 1
|
||||
await getSeriesList()
|
||||
}
|
||||
const handleBrandSizeChange = (val: number) => {
|
||||
brandPagination.pageSize = val
|
||||
getBrandList()
|
||||
}
|
||||
const handleBrandCurrentChange = (val: number) => {
|
||||
brandPagination.currentPage = val
|
||||
getBrandList()
|
||||
}
|
||||
|
||||
const showBrandDialog = (type: 'add' | 'edit', row?: any) => {
|
||||
brandDialogVisible.value = true
|
||||
brandDialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
logourl.value = row.logo_full
|
||||
Object.assign(brandForm, {
|
||||
id: row.id,
|
||||
brand_code: row.brand_code,
|
||||
brand_name: row.brand_name,
|
||||
logo: row.logo,
|
||||
description: row.description,
|
||||
sort: row.sort ?? 0,
|
||||
status: row.status ?? 1
|
||||
})
|
||||
} else {
|
||||
Object.assign(brandForm, {
|
||||
id: '',
|
||||
brand_code: '',
|
||||
brand_name: '',
|
||||
logo: '',
|
||||
description: '',
|
||||
sort: 0,
|
||||
status: 1
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleBrandDelete = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该品牌吗?删除后其系列也可能被清理。', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
const { message } = await vehicleService.brandDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
if (activeBrand.value && activeBrand.value.id === row.id) {
|
||||
activeBrand.value = null
|
||||
seriesTableData.value = []
|
||||
seriesPagination.total = 0
|
||||
}
|
||||
getBrandList()
|
||||
})
|
||||
}
|
||||
const handleBrandSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (brandDialogType.value === 'add') {
|
||||
const { message } = await vehicleService.brandAdd({
|
||||
brand_code: brandForm.brand_code,
|
||||
brand_name: brandForm.brand_name,
|
||||
logo: brandForm.logo,
|
||||
description: brandForm.description,
|
||||
sort: brandForm.sort,
|
||||
status: brandForm.status
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const { message } = await vehicleService.brandEdit(brandForm)
|
||||
ElMessage.success(message)
|
||||
}
|
||||
brandDialogVisible.value = false
|
||||
getBrandList()
|
||||
})
|
||||
}
|
||||
|
||||
// 右侧 系列
|
||||
const seriesLoading = ref(false)
|
||||
const seriesKeyword = ref<string>('')
|
||||
const seriesTableData = ref<any[]>([])
|
||||
const seriesTableRef = ref()
|
||||
const seriesPagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
|
||||
const seriesFormRef = ref<FormInstance>()
|
||||
const seriesDialogVisible = ref(false)
|
||||
const seriesDialogType = ref<'add' | 'edit'>('add')
|
||||
const seriesForm = reactive<any>({
|
||||
series_code: '',
|
||||
series_name: '',
|
||||
description: '',
|
||||
sort: 0,
|
||||
status: 1
|
||||
})
|
||||
const seriesRules = reactive<FormRules>({
|
||||
series_code: [{ required: true, message: '请输入系列编码', trigger: 'blur' }],
|
||||
series_name: [{ required: true, message: '请输入系列名称', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const getSeriesList = async () => {
|
||||
if (!activeBrand.value) return
|
||||
seriesLoading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = seriesPagination
|
||||
const { records, current, size, total } = await vehicleService.getSeriesList({
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: seriesKeyword.value,
|
||||
brand_id: activeBrand.value.id
|
||||
})
|
||||
seriesTableData.value = records
|
||||
Object.assign(seriesPagination, { currentPage: current, pageSize: size, total })
|
||||
} finally {
|
||||
seriesLoading.value = false
|
||||
}
|
||||
}
|
||||
const handleSeriesSizeChange = (val: number) => {
|
||||
seriesPagination.pageSize = val
|
||||
getSeriesList()
|
||||
}
|
||||
const handleSeriesCurrentChange = (val: number) => {
|
||||
seriesPagination.currentPage = val
|
||||
getSeriesList()
|
||||
}
|
||||
const showSeriesDialog = (type: 'add' | 'edit', row?: any) => {
|
||||
seriesDialogVisible.value = true
|
||||
seriesDialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
Object.assign(seriesForm, {
|
||||
id: row.id,
|
||||
series_code: row.series_code,
|
||||
series_name: row.series_name,
|
||||
description: row.description,
|
||||
sort: row.sort ?? 0,
|
||||
status: row.status ?? 1
|
||||
})
|
||||
} else {
|
||||
Object.assign(seriesForm, {
|
||||
id: '',
|
||||
series_code: '',
|
||||
series_name: '',
|
||||
description: '',
|
||||
sort: 0,
|
||||
status: 1
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleSeriesDelete = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该系列吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
const { message } = await vehicleService.seriesDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
getSeriesList()
|
||||
})
|
||||
}
|
||||
const handleSeriesSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl || !activeBrand.value) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
if (seriesDialogType.value === 'add') {
|
||||
const { message } = await vehicleService.seriesAdd({
|
||||
brand_id: activeBrand.value.id,
|
||||
series_code: seriesForm.series_code,
|
||||
series_name: seriesForm.series_name,
|
||||
description: seriesForm.description,
|
||||
sort: seriesForm.sort,
|
||||
status: seriesForm.status
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const { message } = await vehicleService.seriesEdit({
|
||||
id: seriesForm.id,
|
||||
brand_id: activeBrand.value.id,
|
||||
series_code: seriesForm.series_code,
|
||||
series_name: seriesForm.series_name,
|
||||
description: seriesForm.description,
|
||||
sort: seriesForm.sort,
|
||||
status: seriesForm.status
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
seriesDialogVisible.value = false
|
||||
getSeriesList()
|
||||
})
|
||||
}
|
||||
|
||||
// Logo上传处理
|
||||
const handleLogoSuccess = (response: any) => {
|
||||
brandForm.logo = response.url || (response.data && response.data.file_name) || ''
|
||||
// 如需同步到 form.picture
|
||||
logourl.value = response.url || (response.data && response.data.file_url) || ''
|
||||
ElMessage.success('Logo上传成功')
|
||||
}
|
||||
|
||||
const beforeLogoUpload = (file: File) => {
|
||||
const isImage = file.type.startsWith('image/')
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
|
||||
if (!isImage) {
|
||||
ElMessage.error('只能上传图片文件!')
|
||||
return false
|
||||
}
|
||||
if (!isLt2M) {
|
||||
ElMessage.error('图片大小不能超过 2MB!')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getBrandList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__empty-block) {
|
||||
height: 100% !important;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.dict-layout {
|
||||
.dict-type-card,
|
||||
.dict-item-card {
|
||||
background: var(--el-bg-color);
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
.left {
|
||||
font-weight: 500;
|
||||
}
|
||||
.right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.muted {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
.type-pagination {
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-logo-cell {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.logo-placeholder {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: var(--el-color-primary-light-8);
|
||||
color: var(--el-color-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo-uploader {
|
||||
:deep(.el-upload) {
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: var(--el-transition-duration-fast);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
}
|
||||
|
||||
.logo-preview {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,357 @@
|
||||
<template>
|
||||
<div class="color-page">
|
||||
<div class="color-toolbar boxshadow">
|
||||
<div class="color-search-group">
|
||||
<el-form-item label="关键字:" label-width="70px">
|
||||
<el-input
|
||||
style="min-width: 120px"
|
||||
v-model="keyword"
|
||||
placeholder="请输入颜色编码或名称"
|
||||
clearable
|
||||
@keyup.enter="getColorList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型:" label-width="50px">
|
||||
<el-select v-model="typeFilter" placeholder="全部类型" clearable style="min-width: 120px">
|
||||
<el-option label="外观颜色" :value="1" />
|
||||
<el-option label="内饰颜色" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态:" label-width="50px">
|
||||
<el-select
|
||||
v-model="statusFilter"
|
||||
placeholder="全部状态"
|
||||
clearable
|
||||
style="min-width: 120px"
|
||||
>
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="停用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-button type="primary" @click="getColorList" v-ripple>搜索</el-button>
|
||||
<el-button @click="resetSearch" v-ripple>重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<ElRow>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton @click="showDialog('add')" v-ripple v-if="hasAuth('color@add')" type="primary">
|
||||
新增颜色
|
||||
</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="颜色编码" prop="color_code" min-width="120" />
|
||||
<ElTableColumn label="颜色名称" prop="color_text" min-width="150" />
|
||||
<ElTableColumn label="类型" prop="type" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.type === 1 ? 'primary' : 'success'">
|
||||
{{ scope.row.type === 1 ? '外观颜色' : '内饰颜色' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="排序" prop="sort" width="80" />
|
||||
<ElTableColumn label="状态" prop="status" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'success' : 'info'">
|
||||
{{ scope.row.status ? '启用' : '停用' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="created_at" min-width="160" />
|
||||
<ElTableColumn fixed="right" label="操作" width="200px">
|
||||
<template #default="scope">
|
||||
<ElRow>
|
||||
<el-button
|
||||
link
|
||||
@click="showDialog('edit', scope.row)"
|
||||
v-if="hasAuth('color@update')"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
@click="deleteColor(scope.row)"
|
||||
v-if="hasAuth('color@destroy')"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增颜色' : '编辑颜色'"
|
||||
align-center
|
||||
width="600px"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="100px" class="form">
|
||||
<ElFormItem label="颜色编码" prop="color_code">
|
||||
<ElInput v-model="form.color_code" placeholder="请输入颜色编码" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="颜色名称" prop="color_text">
|
||||
<ElInput v-model="form.color_text" placeholder="请输入颜色名称" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="类型" prop="type">
|
||||
<el-select v-model="form.type" placeholder="请选择颜色类型" style="width: 100%">
|
||||
<el-option label="外观颜色" :value="1" />
|
||||
<el-option label="内饰颜色" :value="2" />
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="form.sort" :min="0" :max="999" style="width: 100%" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态">
|
||||
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { vehicleService } from '@/api/vehicleApi'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
defineOptions({ name: 'VehicleColor' })
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const dialogVisible = ref(false)
|
||||
const dialogType = ref('add')
|
||||
const formRef = ref<FormInstance>()
|
||||
const keyword = ref<string>('')
|
||||
const typeFilter = ref<number | undefined>(undefined)
|
||||
const statusFilter = ref<number | undefined>(undefined)
|
||||
|
||||
// 表单数据
|
||||
const form = reactive<any>({
|
||||
id: '',
|
||||
color_code: '',
|
||||
color_text: '',
|
||||
type: 1,
|
||||
status: 1,
|
||||
sort: 0
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive<FormRules>({
|
||||
color_code: [{ required: true, message: '请输入颜色编码', trigger: 'blur' }],
|
||||
color_text: [{ required: true, message: '请输入颜色名称', trigger: 'blur' }],
|
||||
type: [{ required: true, message: '请选择颜色类型', trigger: 'change' }]
|
||||
})
|
||||
|
||||
// 分页数据
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref<any[]>([])
|
||||
const tableRef = ref()
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
getColorList()
|
||||
})
|
||||
|
||||
// 监听搜索条件变化
|
||||
watch([keyword, typeFilter, statusFilter], () => {
|
||||
pagination.currentPage = 1
|
||||
getColorList()
|
||||
})
|
||||
|
||||
// 获取颜色列表
|
||||
const getColorList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = pagination
|
||||
const params = {
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: keyword.value
|
||||
}
|
||||
|
||||
const { records, current, size, total } = await vehicleService.getColorList(params)
|
||||
tableData.value = records || []
|
||||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (error) {
|
||||
console.error('获取颜色列表失败:', error)
|
||||
ElMessage.error('获取颜色列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置搜索条件
|
||||
const resetSearch = () => {
|
||||
keyword.value = ''
|
||||
typeFilter.value = undefined
|
||||
statusFilter.value = undefined
|
||||
pagination.currentPage = 1
|
||||
getColorList()
|
||||
}
|
||||
|
||||
// 处理分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getColorList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getColorList()
|
||||
}
|
||||
|
||||
// 显示对话框
|
||||
const showDialog = (type: string, row?: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
// 编辑模式
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
color_code: row.color_code,
|
||||
color_text: row.color_text,
|
||||
type: row.type,
|
||||
status: row.status,
|
||||
sort: row.sort || 0
|
||||
})
|
||||
} else {
|
||||
// 新增模式
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
color_code: '',
|
||||
color_text: '',
|
||||
type: 1,
|
||||
status: 1,
|
||||
sort: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 删除颜色
|
||||
const deleteColor = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该颜色吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const { message } = await vehicleService.colorDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
getColorList()
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
try {
|
||||
if (dialogType.value === 'add') {
|
||||
// 新增
|
||||
const { message } = await vehicleService.colorAdd({
|
||||
color_code: form.color_code,
|
||||
color_text: form.color_text,
|
||||
type: form.type,
|
||||
status: form.status,
|
||||
sort: form.sort
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
// 编辑
|
||||
const { message } = await vehicleService.colorEdit({
|
||||
id: form.id,
|
||||
color_code: form.color_code,
|
||||
color_text: form.color_text,
|
||||
type: form.type,
|
||||
status: form.status,
|
||||
sort: form.sort
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
getColorList()
|
||||
} catch (error) {
|
||||
console.error('操作失败:', error)
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__empty-block) {
|
||||
height: 100% !important;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.color-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.color-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 20px 20px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
|
||||
.color-search-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.el-col2 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,359 @@
|
||||
<template>
|
||||
<div class="modification-page">
|
||||
<div class="modification-toolbar boxshadow">
|
||||
<div class="modification-search-group">
|
||||
<el-form-item label="关键字:" label-width="70px">
|
||||
<el-input
|
||||
style="min-width: 120px"
|
||||
v-model="keyword"
|
||||
placeholder="请输入关键字"
|
||||
clearable
|
||||
@keyup.enter="getModificationList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getModificationList" v-ripple>搜索</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<ElRow>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton
|
||||
@click="showDialog('add')"
|
||||
v-ripple
|
||||
v-if="hasAuth('modification@add')"
|
||||
type="primary"
|
||||
>
|
||||
新增改装项目
|
||||
</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="项目编码" prop="code" min-width="120" />
|
||||
<ElTableColumn label="项目名称" prop="name" min-width="150" />
|
||||
<ElTableColumn label="改装类型" prop="type" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag :type="getTypeTagType(scope.row.type)">
|
||||
{{ getTypeLabel(scope.row.type) }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="排序" prop="sort" width="80" />
|
||||
<ElTableColumn label="状态" prop="status" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'success' : 'info'">
|
||||
{{ scope.row.status ? '启用' : '停用' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="created_at" min-width="160" />
|
||||
<ElTableColumn fixed="right" label="操作" width="200px">
|
||||
<template #default="scope">
|
||||
<ElRow>
|
||||
<el-button link @click="showDialog('edit', scope.row)">编辑</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
@click="deleteModification(scope.row)"
|
||||
v-if="hasAuth('modification@destroy')"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增改装项目' : '编辑改装项目'"
|
||||
align-center
|
||||
width="600px"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="100px" class="form">
|
||||
<ElFormItem label="项目编码" prop="code">
|
||||
<ElInput v-model="form.code" placeholder="请输入改装项目编码" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="项目名称" prop="name">
|
||||
<ElInput v-model="form.name" placeholder="请输入改装项目名称" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="改装类型" prop="type">
|
||||
<el-select v-model="form.type" placeholder="请选择改装类型" style="width: 100%">
|
||||
<el-option label="外观改装" :value="1" />
|
||||
<el-option label="性能改装" :value="2" />
|
||||
<el-option label="内饰改装" :value="3" />
|
||||
<el-option label="电子设备" :value="4" />
|
||||
<el-option label="其他" :value="5" />
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="form.sort" :min="0" :max="999" style="width: 100%" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态">
|
||||
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { vehicleService } from '@/api/vehicleApi'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
defineOptions({ name: 'VehicleModification' })
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const dialogVisible = ref(false)
|
||||
const dialogType = ref('add')
|
||||
const formRef = ref<FormInstance>()
|
||||
const keyword = ref<string>('')
|
||||
const typeFilter = ref<number | undefined>(undefined)
|
||||
const statusFilter = ref<number | undefined>(undefined)
|
||||
|
||||
// 表单数据
|
||||
const form = reactive<any>({
|
||||
id: '',
|
||||
code: '',
|
||||
name: '',
|
||||
type: 1,
|
||||
status: 1,
|
||||
sort: 0
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive<FormRules>({
|
||||
code: [{ required: true, message: '请输入改装项目编码', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '请输入改装项目名称', trigger: 'blur' }],
|
||||
type: [{ required: true, message: '请选择改装类型', trigger: 'change' }]
|
||||
})
|
||||
|
||||
// 分页数据
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref<any[]>([])
|
||||
const tableRef = ref()
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
getModificationList()
|
||||
})
|
||||
|
||||
// 监听搜索条件变化
|
||||
watch([keyword, typeFilter, statusFilter], () => {
|
||||
pagination.currentPage = 1
|
||||
getModificationList()
|
||||
})
|
||||
|
||||
// 获取改装项目列表
|
||||
const getModificationList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = pagination
|
||||
const params = {
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: keyword.value
|
||||
}
|
||||
|
||||
const { records, current, size, total } = await vehicleService.getModificationList(params)
|
||||
tableData.value = records || []
|
||||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (error) {
|
||||
console.error('获取改装项目列表失败:', error)
|
||||
ElMessage.error('获取改装项目列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getModificationList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getModificationList()
|
||||
}
|
||||
|
||||
// 显示对话框
|
||||
const showDialog = (type: string, row?: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
// 编辑模式
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
code: row.code,
|
||||
name: row.name,
|
||||
type: row.type,
|
||||
status: row.status,
|
||||
sort: row.sort || 0
|
||||
})
|
||||
} else {
|
||||
// 新增模式
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
code: '',
|
||||
name: '',
|
||||
type: 1,
|
||||
status: 1,
|
||||
sort: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 删除改装项目
|
||||
const deleteModification = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该改装项目吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const { message } = await vehicleService.modificationDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
getModificationList()
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
try {
|
||||
if (dialogType.value === 'add') {
|
||||
// 新增
|
||||
const { message } = await vehicleService.modificationAdd({
|
||||
code: form.code,
|
||||
name: form.name,
|
||||
type: form.type,
|
||||
status: form.status,
|
||||
sort: form.sort
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
// 编辑
|
||||
const { message } = await vehicleService.modificationEdit({
|
||||
id: form.id,
|
||||
code: form.code,
|
||||
name: form.name,
|
||||
type: form.type,
|
||||
status: form.status,
|
||||
sort: form.sort
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
getModificationList()
|
||||
} catch (error) {
|
||||
console.error('操作失败:', error)
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取类型标签样式
|
||||
const getTypeTagType = (type: number): 'primary' | 'success' | 'warning' | 'info' | 'danger' => {
|
||||
const typeMap: Record<number, 'primary' | 'success' | 'warning' | 'info' | 'danger'> = {
|
||||
1: 'primary', // 外观改装
|
||||
2: 'success', // 性能改装
|
||||
3: 'warning', // 内饰改装
|
||||
4: 'info', // 电子设备
|
||||
5: 'danger' // 其他
|
||||
}
|
||||
return typeMap[type] || 'info'
|
||||
}
|
||||
|
||||
// 获取类型标签文本
|
||||
const getTypeLabel = (type: number) => {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: '外观改装',
|
||||
2: '性能改装',
|
||||
3: '内饰改装',
|
||||
4: '电子设备',
|
||||
5: '其他'
|
||||
}
|
||||
return typeMap[type] || '未知类型'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__empty-block) {
|
||||
height: 100% !important;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modification-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.modification-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 20px 20px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
|
||||
.modification-search-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.el-col2 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,351 @@
|
||||
<template>
|
||||
<div class="port-page">
|
||||
<div class="port-toolbar boxshadow">
|
||||
<div class="toolbar-left">
|
||||
<ElButton @click="showDialog('add')" v-ripple v-if="hasAuth('port@add')" type="primary">创建备货单</ElButton>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
placeholder="请输入客户名称"
|
||||
clearable
|
||||
style="width: 260px"
|
||||
@keyup.enter="getPortList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getPortList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="港口代码" prop="port_code" min-width="120" />
|
||||
<ElTableColumn label="港口名称" prop="port_name" min-width="150" />
|
||||
<ElTableColumn label="国家" prop="country_id" min-width="140">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.country_name }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<!-- <ElTableColumn label="纬度" prop="lat" min-width="100" /> -->
|
||||
<!-- <ElTableColumn label="经度" prop="lng" min-width="100" /> -->
|
||||
<ElTableColumn label="排序" prop="sort" width="80" />
|
||||
<ElTableColumn label="状态" prop="status" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status ? 'success' : 'info'">{{
|
||||
scope.row.status ? '启用' : '停用'
|
||||
}}</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="created_at" min-width="160" />
|
||||
<ElTableColumn fixed="right" label="操作" width="200px">
|
||||
<template #default="scope">
|
||||
<ElRow>
|
||||
<el-button link @click="showDialog('edit', scope.row)" v-if="hasAuth('port@update')"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
@click="deletePort(scope.row)"
|
||||
v-if="hasAuth('port@destroy')"
|
||||
>删除</el-button
|
||||
>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增港口' : '编辑港口'"
|
||||
align-center
|
||||
width="720px"
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="110px" class="form">
|
||||
<ElFormItem label="港口代码" prop="port_code">
|
||||
<ElInput v-model="form.port_code" placeholder="请输入港口代码" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="港口名称" prop="port_name">
|
||||
<ElInput v-model="form.port_name" placeholder="请输入港口名称" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="国家" prop="country_id">
|
||||
<el-select
|
||||
v-model="form.country_id"
|
||||
filterable
|
||||
placeholder="请选择国家"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in countryOptions"
|
||||
:key="item.id"
|
||||
:label="item.cn_addr"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
<!-- <ElFormItem label="纬度" prop="lat">
|
||||
<ElInput v-model="form.lat" placeholder="请输入纬度" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="经度" prop="lng">
|
||||
<ElInput v-model="form.lng" placeholder="请输入经度" />
|
||||
</ElFormItem> -->
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="form.sort" :min="0" :max="9999" style="width: 100%" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="港口描述" prop="description">
|
||||
<ElInput
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
maxlength="300"
|
||||
show-word-limit
|
||||
placeholder="请输入港口描述"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态">
|
||||
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { vehicleService } from '@/api/vehicleApi'
|
||||
import { commonService } from '@/api/commonApi'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
const { hasAuth } = useAuth()
|
||||
defineOptions({ name: 'VehiclePort' })
|
||||
const loading = ref(false)
|
||||
const dialogVisible = ref(false)
|
||||
const dialogType = ref<'add' | 'edit'>('add')
|
||||
const formRef = ref<FormInstance>()
|
||||
const keyword = ref<string>('')
|
||||
const countryFilter = ref<number | undefined>(undefined)
|
||||
const statusFilter = ref<number | undefined>(undefined)
|
||||
|
||||
const countryOptions = ref<any[]>([])
|
||||
const loadCountryOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getCountrySelect()
|
||||
countryOptions.value = res || []
|
||||
} catch (e) {
|
||||
countryOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const form = reactive<any>({
|
||||
id: '',
|
||||
status: 1,
|
||||
sort: 0,
|
||||
port_code: '',
|
||||
port_name: '',
|
||||
lat: '',
|
||||
lng: '',
|
||||
description: '',
|
||||
country_id: undefined
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
port_code: [{ required: true, message: '请输入港口代码', trigger: 'blur' }],
|
||||
port_name: [{ required: true, message: '请输入港口名称', trigger: 'blur' }],
|
||||
country_id: [{ required: true, message: '请选择国家', trigger: 'change' }]
|
||||
})
|
||||
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
})
|
||||
const tableData = ref<any[]>([])
|
||||
const tableRef = ref()
|
||||
|
||||
onMounted(() => {
|
||||
loadCountryOptions()
|
||||
getPortList()
|
||||
})
|
||||
watch([keyword, countryFilter, statusFilter], () => {
|
||||
pagination.currentPage = 1
|
||||
getPortList()
|
||||
})
|
||||
|
||||
const getPortList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const { currentPage, pageSize } = pagination
|
||||
const params = {
|
||||
current: currentPage,
|
||||
size: pageSize,
|
||||
keyword: keyword.value
|
||||
}
|
||||
const { records, current, size, total } = await vehicleService.getPortList(params)
|
||||
tableData.value = records || []
|
||||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (error) {
|
||||
console.error('获取港口列表失败:', error)
|
||||
ElMessage.error('获取港口列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getPortList()
|
||||
}
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getPortList()
|
||||
}
|
||||
|
||||
const showDialog = (type: 'add' | 'edit', row?: any) => {
|
||||
dialogVisible.value = true
|
||||
dialogType.value = type
|
||||
if (type === 'edit' && row) {
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
status: row.status,
|
||||
sort: row.sort ?? 0,
|
||||
port_code: row.port_code,
|
||||
port_name: row.port_name,
|
||||
lat: row.lat,
|
||||
lng: row.lng,
|
||||
description: row.description,
|
||||
country_id: row.country_id
|
||||
})
|
||||
} else {
|
||||
Object.assign(form, {
|
||||
id: '',
|
||||
status: 1,
|
||||
sort: 0,
|
||||
port_code: '',
|
||||
port_name: '',
|
||||
lat: '',
|
||||
lng: '',
|
||||
description: '',
|
||||
country_id: undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const deletePort = (row: any) => {
|
||||
ElMessageBox.confirm('确定删除该港口吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const { message } = await vehicleService.portDelete({ id: row.id })
|
||||
ElMessage.success(message)
|
||||
getPortList()
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
try {
|
||||
if (dialogType.value === 'add') {
|
||||
const { message } = await vehicleService.portAdd({
|
||||
status: form.status,
|
||||
sort: form.sort,
|
||||
port_code: form.port_code,
|
||||
port_name: form.port_name,
|
||||
lat: form.lat,
|
||||
lng: form.lng,
|
||||
description: form.description,
|
||||
country_id: form.country_id
|
||||
})
|
||||
ElMessage.success(message)
|
||||
} else {
|
||||
const { message } = await vehicleService.portEdit({
|
||||
id: form.id,
|
||||
status: form.status,
|
||||
sort: form.sort,
|
||||
port_code: form.port_code,
|
||||
port_name: form.port_name,
|
||||
lat: form.lat,
|
||||
lng: form.lng,
|
||||
description: form.description,
|
||||
country_id: form.country_id
|
||||
})
|
||||
ElMessage.success(message)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
getPortList()
|
||||
} catch (error) {
|
||||
console.error('操作失败:', error)
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getCountryLabel = (id: number | undefined) => {
|
||||
if (!id) return '-'
|
||||
const found = countryOptions.value.find((c: any) => c.id === id)
|
||||
return found ? found.name : id
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-table__empty-block) {
|
||||
height: 100% !important;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.port-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.port-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 20px 20px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.port-search-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.form {
|
||||
padding: 20px 0;
|
||||
}
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
.el-col2 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,952 @@
|
||||
<template>
|
||||
<div class="stocking-add-page">
|
||||
<div class="header boxshadow">
|
||||
<div class="title">合塑实业·汽车事业部-备货单(客户下定)</div>
|
||||
<div class="subtitle">业务员:{{ baseForm.salesman }}</div>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<div class="form-title">
|
||||
<span class="border"></span>
|
||||
<span class="title">基础信息</span>
|
||||
</div>
|
||||
<ElForm :model="baseForm" class="base-form">
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="阿里订单号/PN号">
|
||||
<ElInput v-model="baseForm.pn_no" placeholder="请输入阿里订单号/PN号" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="日期">
|
||||
<ElDatePicker
|
||||
v-model="baseForm.date"
|
||||
type="date"
|
||||
placeholder="请选择日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="清关目的国">
|
||||
<el-select v-model="baseForm.country" filterable placeholder="请选择国家">
|
||||
<el-option
|
||||
v-for="item in countryOptions"
|
||||
:key="item.id"
|
||||
:label="item.cn_addr"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="客户来源">
|
||||
<el-select v-model="baseForm.customer_source" filterable placeholder="请选择客户渠道">
|
||||
<el-option
|
||||
v-for="item in channelOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="客户名称">
|
||||
<ElInput
|
||||
v-model="baseForm.customer_name"
|
||||
placeholder="请选择客户"
|
||||
readonly
|
||||
@click="openCustomerDialog"
|
||||
>
|
||||
<template #append>
|
||||
<ElButton type="primary" text @click.stop="openCustomerDialog">选择</ElButton>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="客户所在国">
|
||||
<el-select v-model="baseForm.country" filterable placeholder="请选择国家">
|
||||
<el-option
|
||||
v-for="item in countryOptions"
|
||||
:key="item.id"
|
||||
:label="item.cn_addr"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</ElForm>
|
||||
</div>
|
||||
<!-- 明细行 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title">
|
||||
<span class="border"></span>
|
||||
<span class="title">订单详情</span>
|
||||
</div>
|
||||
<div class="items-wrap">
|
||||
<div class="item-row" v-for="(item, idx) in items" :key="item.uid">
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="8">
|
||||
<ElFormItem label="车型" label-width="64px">
|
||||
<ElInput
|
||||
v-model="item.model"
|
||||
placeholder="请选择车型"
|
||||
readonly
|
||||
@click="openVehicleDialog(idx)"
|
||||
>
|
||||
<template #append>
|
||||
<ElButton type="primary" text @click.stop="openVehicleDialog(idx)"
|
||||
>选择</ElButton
|
||||
>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="颜色/外饰" label-width="72px">
|
||||
<el-select v-model="item.color_out" filterable placeholder="请选择内容">
|
||||
<ElOption
|
||||
v-for="item in wcolorOptions"
|
||||
:key="item.color_code"
|
||||
:label="item.color_text"
|
||||
:value="item.color_text"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="颜色/内饰" label-width="72px">
|
||||
<el-select v-model="item.color_in" filterable placeholder="请选择内容">
|
||||
<ElOption
|
||||
v-for="item in ncolorOptions"
|
||||
:key="item.color_code"
|
||||
:label="item.color_text"
|
||||
:value="item.color_text"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="8">
|
||||
<ElFormItem label="改装" label-width="52px">
|
||||
<el-select v-model="item.modify" filterable multiple placeholder="请选择内容">
|
||||
<el-option
|
||||
v-for="item in modificationOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="改装费" label-width="60px">
|
||||
<ElInput v-model.number="item.modify_fee" placeholder="请输入改装费">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.modify_fee_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="FOB段运费" label-width="84px">
|
||||
<ElInput v-model.number="item.fob_fee" placeholder="请输入FOB段运费">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.fob_fee_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="单价" label-width="52px">
|
||||
<ElInput v-model.number="item.unit_price" placeholder="请输入单价">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.unit_price_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="总价" label-width="52px">
|
||||
<ElInput v-model.number="item.total_price" placeholder="请输入总价">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.total_price_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="官方指导价" label-width="85px">
|
||||
<ElInput v-model.number="item.guide_price" placeholder="请输入官方指导价">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.guide_price_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="优惠" label-width="52px">
|
||||
<ElInput v-model.number="item.discount" placeholder="请输入优惠额">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.discount_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="手续费" label-width="60px">
|
||||
<ElInput v-model.number="item.helper_fee" placeholder="请输入手续费">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.helper_fee_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="国内运费" label-width="72px">
|
||||
<ElInput v-model.number="item.domestic_freight" placeholder="请输入国内运费">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.domestic_freight_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="港杂费" label-width="60px">
|
||||
<ElInput v-model.number="item.port_fee" placeholder="请输入港杂费">
|
||||
<template #append>
|
||||
<ElSelect v-model="item.port_fee_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="利润" label-width="52px">
|
||||
<ElSelect v-model="item.profit_type" placeholder="请选择" style="width: 100%">
|
||||
<ElOption label="正在计算利润" value="calc" />
|
||||
<ElOption label="已确认" value="ok" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="8">
|
||||
<ElFormItem label="车架号" label-width="70px">
|
||||
<ElInput v-model.number="item.vin" placeholder="请输入" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="合计到岸价" label-width="85px">
|
||||
<ElInput v-model.number="baseForm.total_cif" placeholder="请输入合计到岸价">
|
||||
<template #append>
|
||||
<ElSelect v-model="baseForm.total_cif_currency" style="width: 64px">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="合同汇率" label-width="70px">
|
||||
<ElInput v-model.number="baseForm.customer_source" placeholder="请输入" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<div class="form-title">
|
||||
<span class="border"></span>
|
||||
<span class="title">运输详情</span>
|
||||
</div>
|
||||
<ElForm :model="footForm" class="foot-form">
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="清关人">
|
||||
<ElInput v-model="footForm.contact" placeholder="请输入清关人" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="预计发送日">
|
||||
<ElDatePicker
|
||||
v-model="footForm.plan_ship_date"
|
||||
type="date"
|
||||
placeholder="请选择日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="运输方式">
|
||||
<ElSelect v-model="footForm.transport" placeholder="请选择运输方式">
|
||||
<ElOption label="滚装" value="roll" />
|
||||
<ElOption label="集装箱" value="container" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="国内收货港">
|
||||
<ElSelect v-model="footForm.domestic_receiver" placeholder="请选择国内收货商">
|
||||
<ElOption
|
||||
v-for="p in portOptions"
|
||||
:key="p.port_id"
|
||||
:label="p.port_name"
|
||||
:value="p.port_id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="贸易条款">
|
||||
<ElInput v-model="footForm.trade_term" placeholder="请选择" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="清关目的港">
|
||||
<ElSelect v-model="footForm.trade_term" placeholder="请选择">
|
||||
<ElOption
|
||||
v-for="p in portOptionsall"
|
||||
:key="p.port_id"
|
||||
:label="p.port_name"
|
||||
:value="p.port_id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="6">
|
||||
<ElFormItem label="最迟到港时间">
|
||||
<ElDatePicker
|
||||
v-model="footForm.plan_ship_date"
|
||||
type="date"
|
||||
placeholder="请选择日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</ElForm>
|
||||
</div>
|
||||
<div class="boxshadow">
|
||||
<div class="form-title">
|
||||
<span class="border"></span>
|
||||
<span class="title">计划收款信息</span>
|
||||
</div>
|
||||
<ElForm :model="footForm" label-width="55px" class="foot-form">
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="汇款国">
|
||||
<el-select v-model="footForm.remitter" filterable placeholder="请选择汇款国">
|
||||
<el-option
|
||||
v-for="item in countryOptions"
|
||||
:key="item.id"
|
||||
:label="item.cn_addr"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="日期">
|
||||
<ElDatePicker
|
||||
v-model="footForm.remit_date"
|
||||
type="date"
|
||||
placeholder="请选择日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="币种">
|
||||
<ElSelect v-model="footForm.currency" placeholder="请选择币种">
|
||||
<ElOption
|
||||
v-for="c in currencyOptions"
|
||||
:key="c.currency_code"
|
||||
:label="c.currency_name"
|
||||
:value="c.currency_code"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="账户">
|
||||
<ElSelect v-model="footForm.account" placeholder="请选择账户">
|
||||
<ElOption
|
||||
v-for="item in accountOptions"
|
||||
:key="item.id"
|
||||
:label="item.account_number"
|
||||
:value="item.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="汇款人">
|
||||
<ElInput v-model="footForm.payer" placeholder="请选择汇款人" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="金额">
|
||||
<ElInput v-model.number="footForm.amount" placeholder="请输入金额" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</ElForm>
|
||||
</div>
|
||||
<!-- 上传合同 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title">
|
||||
<span class="border"></span>
|
||||
<span class="title">上传合同</span>
|
||||
</div>
|
||||
<ElUpload drag action="#" :auto-upload="false" :show-file-list="true" class="upload-box">
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">拖拽文件到此处,或点击上传</div>
|
||||
</ElUpload>
|
||||
</div>
|
||||
|
||||
<div class="form-card">
|
||||
<!-- 底部信息 -->
|
||||
<div class="submit-wrap">
|
||||
<ElButton type="primary" size="large" class="submit-btn" @click="handleSubmit"
|
||||
>提交</ElButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 选择车型 弹框 -->
|
||||
<ElDialog
|
||||
v-model="vehicleDialog.visible"
|
||||
title="选择车辆"
|
||||
width="900px"
|
||||
:close-on-click-modal="false"
|
||||
top="40px"
|
||||
>
|
||||
<div
|
||||
class="search-toolbar"
|
||||
style="margin-bottom: 12px; display: flex; justify-content: flex-end; gap: 8px"
|
||||
>
|
||||
<el-input
|
||||
v-model="vehicleDialog.search.keyword"
|
||||
placeholder="请输入关键字"
|
||||
clearable
|
||||
style="width: 300px"
|
||||
@keyup.enter="getVehicleList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getVehicleList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<ArtTable
|
||||
:loading="vehicleDialog.loading"
|
||||
:data="vehicleDialog.tableData"
|
||||
:currentPage="vehicleDialog.pagination.currentPage"
|
||||
:pageSize="vehicleDialog.pagination.pageSize"
|
||||
:total="vehicleDialog.pagination.total"
|
||||
@size-change="handleVehicleSizeChange"
|
||||
@current-change="handleVehicleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="品牌" prop="brand_name" align="center" />
|
||||
<ElTableColumn label="车系" prop="series_name" align="center" />
|
||||
<ElTableColumn label="车型/配置" prop="model_name" min-width="160">
|
||||
<template #default="scope">
|
||||
<span class="primary">{{ scope.row.model_name }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="年款" prop="model_year" width="80" align="center" />
|
||||
<ElTableColumn label="指导价" prop="msrp" width="100" align="center" />
|
||||
<ElTableColumn label="操作" width="100" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<ElButton link type="primary" @click="chooseVehicle(scope.row)">选择</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</ElDialog>
|
||||
<!-- 选择客户 弹框 -->
|
||||
<ElDialog
|
||||
v-model="customerDialog.visible"
|
||||
title="选择客户"
|
||||
width="900px"
|
||||
:close-on-click-modal="false"
|
||||
top="40px"
|
||||
>
|
||||
<div
|
||||
class="search-toolbar"
|
||||
style="margin-bottom: 12px; display: flex; justify-content: flex-end; gap: 8px"
|
||||
>
|
||||
<el-input
|
||||
v-model="customerDialog.search.keyword"
|
||||
placeholder="请输入客户名称/电话"
|
||||
clearable
|
||||
style="width: 300px"
|
||||
@keyup.enter="getCustomerList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getCustomerList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<ArtTable
|
||||
:loading="customerDialog.loading"
|
||||
:data="customerDialog.tableData"
|
||||
:currentPage="customerDialog.pagination.currentPage"
|
||||
:pageSize="customerDialog.pagination.pageSize"
|
||||
:total="customerDialog.pagination.total"
|
||||
@size-change="handleCustomerSizeChange"
|
||||
@current-change="handleCustomerCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="客户名称" prop="contacts" />
|
||||
<ElTableColumn label="客户编码" prop="code" />
|
||||
<ElTableColumn label="电话" prop="phone" />
|
||||
<ElTableColumn label="公司" prop="company" />
|
||||
<ElTableColumn label="操作" width="80" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<ElButton link type="primary" @click="chooseCustomer(scope.row)">选择</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { CrmService } from '@/api/crmApi'
|
||||
import { commonService } from '@/api/commonApi'
|
||||
import { vehicleService } from '@/api/vehicleApi'
|
||||
const channelOptions = ref<any>()
|
||||
const countryOptions = ref<any>()
|
||||
const modificationOptions = ref<any>()
|
||||
const currencyOptions = ref<any>()
|
||||
const accountOptions = ref<any>()
|
||||
const customerOptions = ref<any>()
|
||||
const portOptions = ref<any>()
|
||||
const portOptionsall = ref<any>()
|
||||
// 外观颜色
|
||||
const wcolorOptions = ref<Array<any>>([])
|
||||
// 内饰颜色
|
||||
const ncolorOptions = ref<Array<any>>([])
|
||||
//渠道
|
||||
const getgetChannel = async () => {
|
||||
const res = await CrmService.getChannel()
|
||||
channelOptions.value = res || []
|
||||
}
|
||||
//客户下拉
|
||||
const getcustomer = async () => {
|
||||
const res = await commonService.getCustomerSelect()
|
||||
customerOptions.value = res || []
|
||||
}
|
||||
|
||||
//国家
|
||||
const getarea = async () => {
|
||||
const res = await CrmService.getCountry()
|
||||
countryOptions.value = res || []
|
||||
}
|
||||
//改装项
|
||||
const getmodification = async () => {
|
||||
const res = await commonService.getModificationSelect()
|
||||
modificationOptions.value = res || []
|
||||
}
|
||||
//颜色下拉列表
|
||||
const loadColorOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getColorSelect({ type: 1 })
|
||||
wcolorOptions.value = res
|
||||
const response = await commonService.getColorSelect({ type: 2 })
|
||||
ncolorOptions.value = response
|
||||
} catch (error) {
|
||||
console.error('获取颜色列表失败:', error)
|
||||
ElMessage.error('获取颜色列表失败')
|
||||
}
|
||||
}
|
||||
//账户
|
||||
const loadAccountOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getAccountSelect()
|
||||
accountOptions.value = res
|
||||
} catch (error) {
|
||||
console.error('获取账户列表失败:', error)
|
||||
ElMessage.error('获取账户列表失败')
|
||||
}
|
||||
}
|
||||
//币种
|
||||
const loadCurrencyOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getCurrencySelect()
|
||||
currencyOptions.value = res
|
||||
} catch (error) {
|
||||
console.error('获取币种列表失败:', error)
|
||||
ElMessage.error('获取币种列表失败')
|
||||
}
|
||||
}
|
||||
//港口
|
||||
const loadPortOptions = async () => {
|
||||
try {
|
||||
const res = await commonService.getPortSelect({ scene: 'domestic' })
|
||||
const resall = await commonService.getPortSelect({})
|
||||
portOptions.value = res
|
||||
portOptionsall.value = resall
|
||||
} catch (error) {
|
||||
console.error('获取港口列表失败:', error)
|
||||
ElMessage.error('获取港口列表失败')
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
getcustomer()
|
||||
loadCurrencyOptions()
|
||||
getgetChannel()
|
||||
getarea()
|
||||
getmodification()
|
||||
loadColorOptions()
|
||||
loadAccountOptions()
|
||||
loadPortOptions()
|
||||
})
|
||||
const baseForm = reactive({
|
||||
pn_no: '',
|
||||
date: '',
|
||||
country: '',
|
||||
customer_source: '',
|
||||
customer_name: '',
|
||||
salesman: '王玉杰',
|
||||
total_cif: undefined as number | undefined,
|
||||
total_cif_currency: 'USD'
|
||||
})
|
||||
|
||||
|
||||
type ItemRow = {
|
||||
uid: string
|
||||
model: string
|
||||
color_out: string
|
||||
color_in: string
|
||||
modify: string
|
||||
modify_fee: number | undefined
|
||||
modify_fee_currency: string
|
||||
modify_type: string
|
||||
fob_fee: number | undefined
|
||||
fob_fee_currency: string
|
||||
helper_fee: number | undefined
|
||||
helper_fee_currency: string
|
||||
domestic_freight: number | undefined
|
||||
domestic_freight_currency: string
|
||||
port_fee: number | undefined
|
||||
port_fee_currency: string
|
||||
unit_price: number | undefined
|
||||
unit_price_currency: string
|
||||
total_price: number | undefined
|
||||
total_price_currency: string
|
||||
guide_price: number | undefined
|
||||
guide_price_currency: string
|
||||
discount: number | undefined
|
||||
discount_currency: string
|
||||
contract_rate: number | undefined
|
||||
profit_type: string
|
||||
vin: string
|
||||
}
|
||||
|
||||
const newItem = (): ItemRow => ({
|
||||
uid: Math.random().toString(36).slice(2),
|
||||
model: '',
|
||||
color_out: '',
|
||||
color_in: '',
|
||||
modify: '',
|
||||
modify_fee: undefined,
|
||||
modify_fee_currency: 'USD',
|
||||
modify_type: '',
|
||||
fob_fee: undefined,
|
||||
fob_fee_currency: 'USD',
|
||||
helper_fee: undefined,
|
||||
helper_fee_currency: 'USD',
|
||||
domestic_freight: undefined,
|
||||
domestic_freight_currency: 'USD',
|
||||
port_fee: undefined,
|
||||
port_fee_currency: 'USD',
|
||||
unit_price: undefined,
|
||||
unit_price_currency: 'USD',
|
||||
total_price: undefined,
|
||||
total_price_currency: 'USD',
|
||||
guide_price: undefined,
|
||||
guide_price_currency: 'USD',
|
||||
discount: undefined,
|
||||
discount_currency: 'USD',
|
||||
contract_rate: 7.16,
|
||||
profit_type: 'calc',
|
||||
vin: ''
|
||||
})
|
||||
|
||||
const items = ref<ItemRow[]>([newItem(), newItem()])
|
||||
|
||||
const footForm = reactive({
|
||||
contact: '',
|
||||
plan_ship_date: '',
|
||||
transport: '',
|
||||
domestic_receiver: '',
|
||||
trade_term: '',
|
||||
remitter: '',
|
||||
remit_date: '',
|
||||
currency: 'CNY',
|
||||
account: '',
|
||||
payer: '',
|
||||
amount: undefined as number | undefined
|
||||
})
|
||||
|
||||
const handleSubmit = () => {
|
||||
const payload = { baseForm, items: items.value, footForm }
|
||||
console.log('submit payload', payload)
|
||||
ElMessage.success('提交成功')
|
||||
}
|
||||
// 选择客户弹框逻辑
|
||||
const customerDialog = reactive({
|
||||
visible: false,
|
||||
search: { keyword: '' },
|
||||
loading: false,
|
||||
tableData: [] as any[],
|
||||
pagination: { currentPage: 1, pageSize: 10, total: 0 }
|
||||
})
|
||||
const openCustomerDialog = () => {
|
||||
customerDialog.visible = true
|
||||
customerDialog.pagination.currentPage = 1
|
||||
getCustomerList()
|
||||
}
|
||||
const getCustomerList = async () => {
|
||||
customerDialog.loading = true
|
||||
try {
|
||||
const { currentPage, pageSize } = customerDialog.pagination
|
||||
const params = { current: currentPage, size: pageSize, keyword: customerDialog.search.keyword }
|
||||
const { data, current, size, total } = await CrmService.getcustomerList(params as any)
|
||||
customerDialog.tableData = data || []
|
||||
Object.assign(customerDialog.pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (e) {
|
||||
} finally {
|
||||
customerDialog.loading = false
|
||||
}
|
||||
}
|
||||
const handleCustomerSizeChange = (size: number) => {
|
||||
customerDialog.pagination.pageSize = size
|
||||
getCustomerList()
|
||||
}
|
||||
const handleCustomerCurrentChange = (page: number) => {
|
||||
customerDialog.pagination.currentPage = page
|
||||
getCustomerList()
|
||||
}
|
||||
const chooseCustomer = (row: any) => {
|
||||
baseForm.customer_name = row.contacts || row.name || ''
|
||||
customerDialog.visible = false
|
||||
}
|
||||
|
||||
// 选择车型弹框逻辑
|
||||
const vehicleDialog = reactive({
|
||||
visible: false,
|
||||
targetIndex: -1,
|
||||
search: { keyword: '' },
|
||||
loading: false,
|
||||
tableData: [] as any[],
|
||||
pagination: { currentPage: 1, pageSize: 10, total: 0 }
|
||||
})
|
||||
|
||||
const openVehicleDialog = (index: number) => {
|
||||
vehicleDialog.targetIndex = index
|
||||
vehicleDialog.visible = true
|
||||
vehicleDialog.pagination.currentPage = 1
|
||||
getVehicleList()
|
||||
}
|
||||
|
||||
const getVehicleList = async () => {
|
||||
vehicleDialog.loading = true
|
||||
try {
|
||||
const { currentPage, pageSize } = vehicleDialog.pagination
|
||||
const params = { current: currentPage, size: pageSize, keyword: vehicleDialog.search.keyword }
|
||||
const { records, current, size, total } = await vehicleService.getVehicleList(params)
|
||||
vehicleDialog.tableData = records || []
|
||||
Object.assign(vehicleDialog.pagination, { currentPage: current, pageSize: size, total })
|
||||
} catch (e) {
|
||||
ElMessage.error('获取车辆列表失败')
|
||||
} finally {
|
||||
vehicleDialog.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleVehicleSizeChange = (size: number) => {
|
||||
vehicleDialog.pagination.pageSize = size
|
||||
getVehicleList()
|
||||
}
|
||||
const handleVehicleCurrentChange = (page: number) => {
|
||||
vehicleDialog.pagination.currentPage = page
|
||||
getVehicleList()
|
||||
}
|
||||
|
||||
const chooseVehicle = (row: any) => {
|
||||
const idx = vehicleDialog.targetIndex
|
||||
if (idx >= 0 && idx < items.value.length) {
|
||||
const target = items.value[idx]
|
||||
target.model = row.model_name || row.name || ''
|
||||
// 回显颜色与指导价
|
||||
target.color_out = row.color_exterior_text || ''
|
||||
target.color_in = row.color_interior_text || ''
|
||||
target.guide_price = row.msrp ?? target.guide_price
|
||||
if (row.currency) {
|
||||
target.guide_price_currency = row.currency
|
||||
}
|
||||
// 可按需带出更多字段回显
|
||||
}
|
||||
vehicleDialog.visible = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-input-group--append .el-input-group__append .el-select .el-select__wrapper) {
|
||||
padding: 4px;
|
||||
}
|
||||
:deep(.el-select__selected-item span) {
|
||||
font-size: 12px;
|
||||
}
|
||||
.form-title {
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.form-title .title {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.stocking-add-page {
|
||||
// background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.items-wrap {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.row-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.row-actions span {
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row-actions .primary {
|
||||
color: var(--el-color-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
.row-actions .danger {
|
||||
color: var(--el-color-danger);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.submit-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 24px 0 8px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 220px;
|
||||
height: 44px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.upload-box { width: 160px; }
|
||||
</style>
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="stocking-page">
|
||||
<div class="stocking-toolbar boxshadow">
|
||||
<div class="toolbar-left">
|
||||
<ElButton type="primary" v-ripple @click="handleCreate">创建备货单</ElButton>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
placeholder="请输入客户名称"
|
||||
clearable
|
||||
style="width: 260px"
|
||||
@keyup.enter="getList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="boxshadow">
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="备货单编号" prop="stock_no" min-width="140" />
|
||||
<ElTableColumn label="阿里订单号/PN号" prop="order_no" min-width="160" />
|
||||
<ElTableColumn label="客户名称" prop="customer_name" min-width="120" />
|
||||
<ElTableColumn label="客户来源" prop="customer_source" min-width="120" />
|
||||
<ElTableColumn label="业务员" prop="salesman" min-width="100" />
|
||||
<ElTableColumn label="日期" prop="date" min-width="120" />
|
||||
<ElTableColumn label="补充" prop="remark" min-width="160" />
|
||||
<ElTableColumn label="状态" prop="status" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag type="success">备货完成</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="操作" fixed="right" min-width="220" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow :gutter="10" justify="center">
|
||||
<el-button link type="primary" @click="handleView(scope.row)">查看备货单</el-button>
|
||||
<el-button link type="primary" @click="handleCreateRepair(scope.row)"
|
||||
>创建终版备货单</el-button
|
||||
>
|
||||
<el-button link type="primary" @click="handleView1(scope.row)"
|
||||
>查看终版备货单</el-button
|
||||
>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { router } from '@/router'
|
||||
|
||||
const loading = ref(false)
|
||||
const keyword = ref('')
|
||||
const tableRef = ref()
|
||||
const tableData = ref<any[]>([])
|
||||
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
watch([keyword], () => {
|
||||
pagination.currentPage = 1
|
||||
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 这里先使用本地假数据占位,等后端接口确定后再切换为真实请求
|
||||
const mock = Array.from({ length: 8 }).map((_, i) => ({
|
||||
id: i + 1,
|
||||
stock_no: `HSAT-JN00${(i + 10).toString().padStart(2, '0')}`,
|
||||
order_no: 'VCS28762JN2',
|
||||
customer_name: 'Alicia',
|
||||
customer_source: '广交会',
|
||||
salesman: '王玉凯',
|
||||
date: '2025-08-27',
|
||||
remark: 'XXXXXXXXXXXX',
|
||||
status: 1,
|
||||
}))
|
||||
tableData.value = mock
|
||||
pagination.total = 24
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.pageSize = size
|
||||
getList()
|
||||
}
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.currentPage = page
|
||||
getList()
|
||||
}
|
||||
|
||||
const handleCreate = () => {
|
||||
// TODO: 跳转到创建备货单页面
|
||||
router.push('/crmpc/stocking_list/Add')
|
||||
}
|
||||
const handleView = (row: any) => {
|
||||
router.push('/crmpc/stocking_list/show')
|
||||
// TODO: 跳转或弹窗查看备货单
|
||||
}
|
||||
const handleView1 = (row: any) => {
|
||||
router.push('/crmpc/stocking_list/final_show')
|
||||
// TODO: 跳转或弹窗查看备货单
|
||||
}
|
||||
const handleCreateRepair = (row: any) => {
|
||||
router.push('/crmpc/stocking_list/final')
|
||||
// TODO: 跳转创建维修保单
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stocking-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.stocking-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 16px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.clickable { cursor: pointer; }
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,535 @@
|
||||
<template>
|
||||
<div class="stocking-final-show-page">
|
||||
<div class="header boxshadow">
|
||||
<div class="header-left">
|
||||
<div class="title">合塑实业·汽车事业部-备货单(客户下定)</div>
|
||||
<div class="sub">备货单编号:{{ header.order_no }} 业务员:{{ header.salesman }}</div>
|
||||
</div>
|
||||
<ElButton type="primary" plain @click="handlePrint">打印整单</ElButton>
|
||||
</div>
|
||||
|
||||
<!-- 基础信息 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">基础信息</span></div>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="5"><ElFormItem label="阿里订单号/PN号"><ElInput v-model="base.pn_no" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="日期"><ElInput v-model="base.date" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="关闭日期"><ElInput v-model="base.close_date" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="3"><ElFormItem label="客户来源"><ElInput v-model="base.channel" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="客户名称"><ElInput v-model="base.customer_name" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="客户所在国"><ElInput v-model="base.client_country" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<!-- 订单详情 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">订单详情</span></div>
|
||||
<div class="items-wrap">
|
||||
<div class="item-row" v-for="(item, idx) in items" :key="idx">
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="8"><ElFormItem label="车型" label-width="64px"><ElInput v-model="item.model" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="颜色/外" label-width="72px"><ElInput v-model="item.color_out" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="内饰" label-width="52px"><ElInput v-model="item.color_in" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="8"><ElFormItem label="改装" label-width="52px"><ElInput v-model="item.modify" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4"><ElFormItem label="改装费" label-width="60px"><ElInput v-model="item.modify_fee" disabled><template #append>{{ item.modify_fee_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="FOB段运费" label-width="84px"><ElInput v-model="item.fob_fee" disabled><template #append>{{ item.fob_fee_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="单价" label-width="52px"><ElInput v-model="item.unit_price" disabled><template #append>{{ item.unit_price_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="总价" label-width="52px"><ElInput v-model="item.total_price" disabled><template #append>{{ item.total_price_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="官方指导价" label-width="85px"><ElInput v-model="item.guide_price" disabled><template #append>{{ item.guide_price_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="优惠" label-width="52px"><ElInput v-model="item.discount" disabled><template #append>{{ item.discount_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4"><ElFormItem label="手续费" label-width="60px"><ElInput v-model="item.helper_fee" disabled><template #append>{{ item.helper_fee_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="国内运费" label-width="72px"><ElInput v-model="item.domestic_freight" disabled><template #append>{{ item.domestic_freight_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="港杂费" label-width="60px"><ElInput v-model="item.port_fee" disabled><template #append>{{ item.port_fee_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="利润" label-width="52px"><ElInput v-model="item.profit" disabled><template #append>{{ item.profit_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="车架号" label-width="60px"><ElInput v-model="item.vin" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="5"><ElFormItem label="合计到岸价" label-width="85px"><ElInput v-model="base.total_cif" disabled><template #append>{{ base.total_cif_currency }}</template></ElInput></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="合同汇率" label-width="70px"><ElInput v-model="base.contract_rate" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 运输详情 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">运输详情</span></div>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4"><ElFormItem label="清关人"><ElInput v-model="ship.customs" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="预计发送日"><ElInput v-model="ship.plan" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="运输方式"><ElInput v-model="ship.method" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="国内收货港"><ElInput v-model="ship.domestic_port" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="8"><ElFormItem label="贸易条款/清关目的港"><ElInput v-model="ship.terms" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="6"><ElFormItem label="最迟到港时间"><ElInput v-model="ship.latest_arrival" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<!-- 计划收款信息 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">计划收款信息</span></div>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4"><ElFormItem label="汇款国"><ElInput v-model="pay.remit_country" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="日期"><ElInput v-model="pay.date" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="币种"><ElInput v-model="pay.currency" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="账户"><ElInput v-model="pay.account" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="汇款人"><ElInput v-model="pay.payer" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="金额"><ElInput v-model="pay.amount" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<!-- 上传合同 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">上传合同</span></div>
|
||||
<div class="upload-box">
|
||||
<img class="preview" src="@/assets/img/common/logo.webp" alt="file" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const header = reactive({ order_no: 'HSAT-JN00010', salesman: '王玉杰' })
|
||||
|
||||
// 打印功能
|
||||
const handlePrint = () => {
|
||||
// 创建一个新的窗口用于打印
|
||||
const printWindow = window.open('', '_blank')
|
||||
if (!printWindow) return
|
||||
|
||||
// 构建表格行数据
|
||||
const tableRows = items.value.map((item, index) => {
|
||||
return `
|
||||
<tr>
|
||||
<td>${index + 1}</td>
|
||||
<td class="text-left">${item.model}</td>
|
||||
<td>1</td>
|
||||
<td>${item.color_out}</td>
|
||||
<td>${item.color_in}</td>
|
||||
<td class="text-left">${item.modify}</td>
|
||||
<td>$${item.unit_price}</td>
|
||||
<td>$${item.total_price}</td>
|
||||
<td>${item.guide_price}</td>
|
||||
<td>${item.discount}</td>
|
||||
</tr>
|
||||
`
|
||||
}).join('')
|
||||
|
||||
// 构建打印页面的HTML
|
||||
const printHTML = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>备货单打印</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: #333;
|
||||
}
|
||||
.print-container {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 2px solid #333;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.main-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.order-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.order-info-left, .order-info-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.info-label {
|
||||
font-weight: bold;
|
||||
margin-right: 5px;
|
||||
min-width: 60px;
|
||||
}
|
||||
.info-value {
|
||||
flex: 1;
|
||||
}
|
||||
.order-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.order-table th,
|
||||
.order-table td {
|
||||
border: 1px solid #333;
|
||||
padding: 4px 6px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.order-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
}
|
||||
.order-table .text-left {
|
||||
text-align: left;
|
||||
}
|
||||
.summary-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.summary-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.summary-label {
|
||||
font-weight: bold;
|
||||
min-width: 100px;
|
||||
}
|
||||
.shipping-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.shipping-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.shipping-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.shipping-label {
|
||||
font-weight: bold;
|
||||
margin-right: 5px;
|
||||
min-width: 80px;
|
||||
}
|
||||
.payment-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 11px;
|
||||
}
|
||||
.payment-table th,
|
||||
.payment-table td {
|
||||
border: 1px solid #333;
|
||||
padding: 4px 6px;
|
||||
text-align: center;
|
||||
}
|
||||
.payment-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
}
|
||||
@media print {
|
||||
body { -webkit-print-color-adjust: exact; }
|
||||
.print-container { padding: 10px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="print-container">
|
||||
<!-- 标题 -->
|
||||
<div class="header">
|
||||
<div class="main-title">合塑实业-汽车事业部-备货单(客户下定)</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单基本信息 -->
|
||||
<div class="order-info">
|
||||
<div class="order-info-left">
|
||||
<div class="info-item">
|
||||
<span class="info-label">备货单编号:</span>
|
||||
<span class="info-value">${header.order_no}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">阿里订单号/PI号:</span>
|
||||
<span class="info-value">${base.pn_no}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">日期:</span>
|
||||
<span class="info-value">${base.date}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-info-right">
|
||||
<div class="info-item">
|
||||
<span class="info-label">业务员:</span>
|
||||
<span class="info-value">${header.salesman}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">客户名称:</span>
|
||||
<span class="info-value">${base.customer_name}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">客户来源:</span>
|
||||
<span class="info-value">${base.channel}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">关目的国:</span>
|
||||
<span class="info-value">${base.client_country}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">客户所在国:</span>
|
||||
<span class="info-value">${base.client_country}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单详情表格 -->
|
||||
<table class="order-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>编号</th>
|
||||
<th>车型</th>
|
||||
<th>数量/台</th>
|
||||
<th>颜色/外</th>
|
||||
<th>内饰</th>
|
||||
<th>改装</th>
|
||||
<th>单价(美金)</th>
|
||||
<th>总价(美金)</th>
|
||||
<th>官方指导价</th>
|
||||
<th>优惠</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${tableRows}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 汇总信息 -->
|
||||
<div class="summary-section">
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">合同汇率:</span>
|
||||
<span>${base.contract_rate}</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span class="summary-label">合计到岸价:</span>
|
||||
<span>$${base.total_cif}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 运输信息 -->
|
||||
<div class="shipping-info">
|
||||
<div class="shipping-grid">
|
||||
<div class="shipping-item">
|
||||
<span class="shipping-label">清关人:</span>
|
||||
<span>${ship.customs}</span>
|
||||
</div>
|
||||
<div class="shipping-item">
|
||||
<span class="shipping-label">预计发运日期:</span>
|
||||
<span>${ship.plan}</span>
|
||||
</div>
|
||||
<div class="shipping-item">
|
||||
<span class="shipping-label">出运方式:</span>
|
||||
<span>${ship.method}</span>
|
||||
</div>
|
||||
<div class="shipping-item">
|
||||
<span class="shipping-label">国内收货港:</span>
|
||||
<span>${ship.domestic_port}</span>
|
||||
</div>
|
||||
<div class="shipping-item">
|
||||
<span class="shipping-label">贸易条款/清关目的港:</span>
|
||||
<span>${ship.terms}</span>
|
||||
</div>
|
||||
<div class="shipping-item">
|
||||
<span class="shipping-label">最迟到港时间:</span>
|
||||
<span>${ship.latest_arrival}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 计划收款信息 -->
|
||||
<div style="margin-top: 20px;">
|
||||
<h4 style="margin-bottom: 10px; font-size: 13px;">计划收款信息</h4>
|
||||
<table class="payment-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th>
|
||||
<th>汇款国</th>
|
||||
<th>日期</th>
|
||||
<th>币种</th>
|
||||
<th>账户</th>
|
||||
<th>汇款人</th>
|
||||
<th>金额</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>收款1</td>
|
||||
<td>${pay.remit_country}</td>
|
||||
<td>${pay.date}</td>
|
||||
<td>${pay.currency}</td>
|
||||
<td>${pay.account}</td>
|
||||
<td class="text-left">${pay.payer}</td>
|
||||
<td>$${pay.amount}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
// 写入HTML内容
|
||||
printWindow.document.write(printHTML)
|
||||
printWindow.document.close()
|
||||
|
||||
// 等待内容加载完成后打印
|
||||
setTimeout(() => {
|
||||
printWindow.print()
|
||||
printWindow.close()
|
||||
}, 500)
|
||||
}
|
||||
const base = reactive({
|
||||
pn_no: 'VCSC250827JN1',
|
||||
date: '2025-08-28',
|
||||
close_date: '',
|
||||
channel: '广交会',
|
||||
customer_name: 'Ailcia',
|
||||
client_country: '密鲁',
|
||||
total_cif: '60,652.00',
|
||||
total_cif_currency: '美元',
|
||||
contract_rate: '7.16'
|
||||
})
|
||||
const items = ref([
|
||||
{
|
||||
model: '丰田卡罗拉锐放汽油 2024款 2.0L CVT 精英版',
|
||||
color_out: '银',
|
||||
color_in: '黑',
|
||||
modify: '改装仿皮座椅',
|
||||
modify_fee: '1000',
|
||||
modify_fee_currency: '美元',
|
||||
fob_fee: '500',
|
||||
fob_fee_currency: '美元',
|
||||
unit_price: '14,545.00',
|
||||
unit_price_currency: '美元',
|
||||
total_price: '14,545.00',
|
||||
total_price_currency: '美元',
|
||||
guide_price: '139800',
|
||||
guide_price_currency: '人民币',
|
||||
discount: '42000郑州',
|
||||
discount_currency: '人民币',
|
||||
helper_fee: '1500',
|
||||
helper_fee_currency: '美元',
|
||||
domestic_freight: '1500',
|
||||
domestic_freight_currency: '美元',
|
||||
port_fee: '600',
|
||||
port_fee_currency: '美元',
|
||||
profit: '1000',
|
||||
profit_currency: '美元',
|
||||
vin: 'S4412454142142141'
|
||||
},
|
||||
{
|
||||
model: '丰田卡罗拉锐放汽油 2024款 2.0L CVT 精英版',
|
||||
color_out: '银',
|
||||
color_in: '黑',
|
||||
modify: '改装仿皮座椅',
|
||||
modify_fee: '1000',
|
||||
modify_fee_currency: '美元',
|
||||
fob_fee: '500',
|
||||
fob_fee_currency: '美元',
|
||||
unit_price: '14,545.00',
|
||||
unit_price_currency: '美元',
|
||||
total_price: '14,545.00',
|
||||
total_price_currency: '美元',
|
||||
guide_price: '139800',
|
||||
guide_price_currency: '人民币',
|
||||
discount: '42000郑州',
|
||||
discount_currency: '人民币',
|
||||
helper_fee: '1500',
|
||||
helper_fee_currency: '美元',
|
||||
domestic_freight: '1500',
|
||||
domestic_freight_currency: '美元',
|
||||
port_fee: '600',
|
||||
port_fee_currency: '美元',
|
||||
profit: '1000',
|
||||
profit_currency: '美元',
|
||||
vin: 'S4412454142142141'
|
||||
},
|
||||
{
|
||||
model: '丰田卡罗拉锐放汽油 2024款 2.0L CVT 精英版',
|
||||
color_out: '银',
|
||||
color_in: '黑',
|
||||
modify: '改装仿皮座椅',
|
||||
modify_fee: '1000',
|
||||
modify_fee_currency: '美元',
|
||||
fob_fee: '500',
|
||||
fob_fee_currency: '美元',
|
||||
unit_price: '14,545.00',
|
||||
unit_price_currency: '美元',
|
||||
total_price: '14,545.00',
|
||||
total_price_currency: '美元',
|
||||
guide_price: '139800',
|
||||
guide_price_currency: '人民币',
|
||||
discount: '42000郑州',
|
||||
discount_currency: '人民币',
|
||||
helper_fee: '1500',
|
||||
helper_fee_currency: '美元',
|
||||
domestic_freight: '1500',
|
||||
domestic_freight_currency: '美元',
|
||||
port_fee: '600',
|
||||
port_fee_currency: '美元',
|
||||
profit: '1000',
|
||||
profit_currency: '美元',
|
||||
vin: 'S4412454142142141'
|
||||
}
|
||||
])
|
||||
const ship = reactive({ customs: '陆云鹤', plan: '2025-08-28', method: '海运', domestic_port: 'shanghai', terms: 'FOB shanghai', latest_arrival: '2025-9-03' })
|
||||
const pay = reactive({ remit_country: '香港', date: '2028-9-01', currency: '美元', account: '中行1451', payer: 'AMOTOR TECHNOLOGY CO. LIMITED/XTRANSFER LIMITED', amount: '15,000.00' })
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stocking-final-show-page { min-height: 100vh; }
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.header-left {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.sub {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
}
|
||||
.form-title { font-weight: bold; color: #222; margin-bottom: 15px; }
|
||||
.form-title .title { margin-left: 6px; }
|
||||
.items-wrap { margin-top: 6px; }
|
||||
.item-row { padding: 8px 0; }
|
||||
.upload-box { padding: 12px; }
|
||||
.upload-box .preview { width: 120px; height: 120px; object-fit: cover; border: 1px dashed var(--el-border-color); border-radius: 6px; }
|
||||
:deep(.el-input.is-disabled .el-input__inner) { color: var(--el-text-color-regular); }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<div class="stocking-show-page">
|
||||
<div class="header boxshadow">
|
||||
<div class="header-left">
|
||||
<div class="title">合塑实业·汽车事业部-备货单(客户下定)</div>
|
||||
<div class="sub">
|
||||
<span class="mr40">备货单编号:{{ header.order_no }}</span>
|
||||
<span>业务员:{{ header.salesman }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ElButton type="primary" plain>打印整单</ElButton>
|
||||
</div>
|
||||
|
||||
<!-- 基础信息 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">基础信息</span></div>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="5">
|
||||
<ElFormItem label="阿里订单号/PN号">
|
||||
<ElInput v-model="base.pn_no" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="日期">
|
||||
<ElInput v-model="base.date" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="关闭日期">
|
||||
<ElInput v-model="base.close_date" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="3">
|
||||
<ElFormItem label="客户来源">
|
||||
<ElInput v-model="base.channel" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="客户名称">
|
||||
<ElInput v-model="base.customer_name" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="客户所在国">
|
||||
<ElInput v-model="base.client_country" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<!-- 订单详情 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">订单详情</span></div>
|
||||
<div class="items-wrap">
|
||||
<div class="item-row" v-for="(item, idx) in items" :key="idx">
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="8">
|
||||
<ElFormItem label="车型" label-width="64px">
|
||||
<ElInput v-model="item.model" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="颜色/外" label-width="72px">
|
||||
<ElInput v-model="item.color_out" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="内饰" label-width="52px">
|
||||
<ElInput v-model="item.color_in" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="8">
|
||||
<ElFormItem label="改装" label-width="52px">
|
||||
<ElInput v-model="item.modify" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="改装费" label-width="60px">
|
||||
<ElInput v-model="item.modify_fee" disabled>
|
||||
<template #append>{{ item.modify_fee_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="FOB段运费" label-width="84px">
|
||||
<ElInput v-model="item.fob_fee" disabled>
|
||||
<template #append>{{ item.fob_fee_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="单价" label-width="52px">
|
||||
<ElInput v-model="item.unit_price" disabled>
|
||||
<template #append>{{ item.unit_price_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="总价" label-width="52px">
|
||||
<ElInput v-model="item.total_price" disabled>
|
||||
<template #append>{{ item.total_price_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="官方指导价" label-width="85px">
|
||||
<ElInput v-model="item.guide_price" disabled>
|
||||
<template #append>{{ item.guide_price_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="优惠" label-width="52px">
|
||||
<ElInput v-model="item.discount" disabled>
|
||||
<template #append>{{ item.discount_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="手续费" label-width="60px">
|
||||
<ElInput v-model="item.helper_fee" disabled>
|
||||
<template #append>{{ item.helper_fee_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="国内运费" label-width="72px">
|
||||
<ElInput v-model="item.domestic_freight" disabled>
|
||||
<template #append>{{ item.domestic_freight_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="港杂费" label-width="60px">
|
||||
<ElInput v-model="item.port_fee" disabled>
|
||||
<template #append>{{ item.port_fee_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="利润" label-width="52px">
|
||||
<ElInput v-model="item.profit" disabled>
|
||||
<template #append>{{ item.profit_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="5">
|
||||
<ElFormItem label="合计到岸价" label-width="85px">
|
||||
<ElInput v-model="base.total_cif" disabled>
|
||||
<template #append>{{ base.total_cif_currency }}</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="4">
|
||||
<ElFormItem label="合同汇率" label-width="70px">
|
||||
<ElInput v-model="base.contract_rate" disabled />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 运输详情 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">运输详情</span></div>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4"><ElFormItem label="清关人"><ElInput v-model="ship.customs" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="预计发送日"><ElInput v-model="ship.plan" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="运输方式"><ElInput v-model="ship.method" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="国内收货港"><ElInput v-model="ship.domestic_port" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="8"><ElFormItem label="贸易条款/清关目的港"><ElInput v-model="ship.terms" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="6"><ElFormItem label="最迟到港时间"><ElInput v-model="ship.latest_arrival" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
|
||||
<!-- 计划收款信息 -->
|
||||
<div class="boxshadow">
|
||||
<div class="form-title"><span class="border"></span><span class="title">计划收款信息</span></div>
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="4"><ElFormItem label="汇款国"><ElInput v-model="pay.remit_country" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="日期"><ElInput v-model="pay.date" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="币种"><ElInput v-model="pay.currency" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="账户"><ElInput v-model="pay.account" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="汇款人"><ElInput v-model="pay.payer" disabled /></ElFormItem></ElCol>
|
||||
<ElCol :span="4"><ElFormItem label="金额"><ElInput v-model="pay.amount" disabled /></ElFormItem></ElCol>
|
||||
</ElRow>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const header = reactive({ order_no: 'HSAT-JN00010', salesman: '王玉杰' })
|
||||
const base = reactive({
|
||||
pn_no: 'VCSC250827-JN1',
|
||||
date: '2025-08-31',
|
||||
close_date: '',
|
||||
channel: '广交会',
|
||||
customer_name: 'Alicia',
|
||||
client_country: '埃赫',
|
||||
total_cif: '60,652.00',
|
||||
total_cif_currency: '美元',
|
||||
contract_rate: '7.16'
|
||||
})
|
||||
const items = ref([
|
||||
{
|
||||
model: '丰田卡罗拉 2024款 2.0L CVT 精英版',
|
||||
color_out: '银色',
|
||||
color_in: '黑',
|
||||
modify: '改装仿皮座椅',
|
||||
modify_fee: '1000',
|
||||
modify_fee_currency: '美元',
|
||||
fob_fee: '500',
|
||||
fob_fee_currency: '美元',
|
||||
unit_price: '14,545.00',
|
||||
unit_price_currency: '美元',
|
||||
total_price: '14,545.00',
|
||||
total_price_currency: '美元',
|
||||
guide_price: '139800',
|
||||
guide_price_currency: '人民币',
|
||||
discount: '42000',
|
||||
discount_currency: '人民币',
|
||||
helper_fee: '1500',
|
||||
helper_fee_currency: '美元',
|
||||
domestic_freight: '1500',
|
||||
domestic_freight_currency: '美元',
|
||||
port_fee: '600',
|
||||
port_fee_currency: '美元',
|
||||
profit: '1000',
|
||||
profit_currency: '美元'
|
||||
},
|
||||
{
|
||||
model: '丰田卡罗拉 2024款 2.0L CVT 精英版',
|
||||
color_out: '黑色',
|
||||
color_in: '黑',
|
||||
modify: '改装仿皮座椅',
|
||||
modify_fee: '1000',
|
||||
modify_fee_currency: '美元',
|
||||
fob_fee: '500',
|
||||
fob_fee_currency: '美元',
|
||||
unit_price: '14,545.00',
|
||||
unit_price_currency: '美元',
|
||||
total_price: '14,545.00',
|
||||
total_price_currency: '美元',
|
||||
guide_price: '139800',
|
||||
guide_price_currency: '人民币',
|
||||
discount: '42000',
|
||||
discount_currency: '人民币',
|
||||
helper_fee: '1500',
|
||||
helper_fee_currency: '美元',
|
||||
domestic_freight: '1500',
|
||||
domestic_freight_currency: '美元',
|
||||
port_fee: '600',
|
||||
port_fee_currency: '美元',
|
||||
profit: '1000',
|
||||
profit_currency: '美元'
|
||||
}
|
||||
])
|
||||
const ship = reactive({
|
||||
customs: '陌生人',
|
||||
plan: '2025-08-28',
|
||||
method: '滚装',
|
||||
domestic_port: '上海',
|
||||
terms: '贸易条款展示字段',
|
||||
latest_arrival: '2025-09-03'
|
||||
})
|
||||
const pay = reactive({
|
||||
remit_country: '汇款国',
|
||||
date: '2025-08-28',
|
||||
currency: '美元',
|
||||
account: '中行1451',
|
||||
payer: 'AMOTOR TECHNOLOGY CO., LIMITED/XTRANSFER LIMITED',
|
||||
amount: '15,000.00'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stocking-show-page { min-height: 100vh; }
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 12px;
|
||||
color: #333333;
|
||||
.header-left {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.sub {
|
||||
color: #333333;
|
||||
}
|
||||
.mr40 { margin-right: 40px; }
|
||||
}
|
||||
.form-title { font-weight: bold; color: #222; margin-bottom: 15px; }
|
||||
.form-title .title { margin-left: 6px; }
|
||||
.items-wrap { margin-top: 6px; }
|
||||
.item-row { padding: 8px 0; }
|
||||
:deep(.el-input.is-disabled .el-input__inner) { color: var(--el-text-color-regular); }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="stocking-page">
|
||||
<div class="stocking-toolbar boxshadow">
|
||||
<div class="toolbar-left">
|
||||
<ElButton type="primary" v-ripple @click="handleCreate">创建备货单</ElButton>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
placeholder="请输入客户名称"
|
||||
clearable
|
||||
style="width: 260px"
|
||||
@keyup.enter="getList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="boxshadow">
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="备货单编号" prop="stock_no" min-width="140" />
|
||||
<ElTableColumn label="阿里订单号/PN号" prop="order_no" min-width="160" />
|
||||
<ElTableColumn label="客户名称" prop="customer_name" min-width="120" />
|
||||
<ElTableColumn label="客户来源" prop="customer_source" min-width="120" />
|
||||
<ElTableColumn label="业务员" prop="salesman" min-width="100" />
|
||||
<ElTableColumn label="日期" prop="date" min-width="120" />
|
||||
<ElTableColumn label="补充" prop="remark" min-width="160" />
|
||||
<ElTableColumn label="状态" prop="status" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag type="success">备货完成</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="操作" fixed="right" min-width="220" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow :gutter="10" justify="center">
|
||||
<el-button link type="primary" @click="handleView(scope.row)">查看备货单</el-button>
|
||||
<el-button link type="primary" @click="handleCreateRepair(scope.row)"
|
||||
>创建终版备货单</el-button
|
||||
>
|
||||
<el-button link type="primary" @click="handleView1(scope.row)"
|
||||
>查看终版备货单</el-button
|
||||
>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { router } from '@/router'
|
||||
|
||||
const loading = ref(false)
|
||||
const keyword = ref('')
|
||||
const tableRef = ref()
|
||||
const tableData = ref<any[]>([])
|
||||
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
watch([keyword], () => {
|
||||
pagination.currentPage = 1
|
||||
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 这里先使用本地假数据占位,等后端接口确定后再切换为真实请求
|
||||
const mock = Array.from({ length: 8 }).map((_, i) => ({
|
||||
id: i + 1,
|
||||
stock_no: `HSAT-JN00${(i + 10).toString().padStart(2, '0')}`,
|
||||
order_no: 'VCS28762JN2',
|
||||
customer_name: 'Alicia',
|
||||
customer_source: '广交会',
|
||||
salesman: '王玉凯',
|
||||
date: '2025-08-27',
|
||||
remark: 'XXXXXXXXXXXX',
|
||||
status: 1,
|
||||
}))
|
||||
tableData.value = mock
|
||||
pagination.total = 24
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.pageSize = size
|
||||
getList()
|
||||
}
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.currentPage = page
|
||||
getList()
|
||||
}
|
||||
|
||||
const handleCreate = () => {
|
||||
// TODO: 跳转到创建备货单页面
|
||||
router.push('/crmpc/stocking_list/Add')
|
||||
}
|
||||
const handleView = (row: any) => {
|
||||
router.push('/crmpc/stocking_list/show')
|
||||
// TODO: 跳转或弹窗查看备货单
|
||||
}
|
||||
const handleView1 = (row: any) => {
|
||||
router.push('/crmpc/stocking_list/final_show')
|
||||
// TODO: 跳转或弹窗查看备货单
|
||||
}
|
||||
const handleCreateRepair = (row: any) => {
|
||||
router.push('/crmpc/stocking_list/final')
|
||||
// TODO: 跳转创建维修保单
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stocking-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.stocking-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 16px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.clickable { cursor: pointer; }
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="stocking-page">
|
||||
<div class="stocking-toolbar boxshadow">
|
||||
<div class="toolbar-left">
|
||||
<ElButton type="primary" v-ripple @click="handleCreate">创建备货单</ElButton>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
placeholder="请输入客户名称"
|
||||
clearable
|
||||
style="width: 260px"
|
||||
@keyup.enter="getList"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable" @click="getList"><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="boxshadow">
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn label="备货单编号" prop="stock_no" min-width="140" />
|
||||
<ElTableColumn label="阿里订单号/PN号" prop="order_no" min-width="160" />
|
||||
<ElTableColumn label="客户名称" prop="customer_name" min-width="120" />
|
||||
<ElTableColumn label="客户来源" prop="customer_source" min-width="120" />
|
||||
<ElTableColumn label="业务员" prop="salesman" min-width="100" />
|
||||
<ElTableColumn label="日期" prop="date" min-width="120" />
|
||||
<ElTableColumn label="补充" prop="remark" min-width="160" />
|
||||
<ElTableColumn label="状态" prop="status" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag type="success">备货完成</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="操作" fixed="right" min-width="220" align="center">
|
||||
<template #default="scope">
|
||||
<ElRow :gutter="10" justify="center">
|
||||
<el-button link type="primary" @click="handleView(scope.row)">查看备货单</el-button>
|
||||
<el-button link type="primary" @click="handleCreateRepair(scope.row)"
|
||||
>创建终版备货单</el-button
|
||||
>
|
||||
<el-button link type="primary" @click="handleView1(scope.row)"
|
||||
>查看终版备货单</el-button
|
||||
>
|
||||
</ElRow>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { router } from '@/router'
|
||||
|
||||
const loading = ref(false)
|
||||
const keyword = ref('')
|
||||
const tableRef = ref()
|
||||
const tableData = ref<any[]>([])
|
||||
const pagination = reactive({ currentPage: 1, pageSize: 10, total: 0 })
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
watch([keyword], () => {
|
||||
pagination.currentPage = 1
|
||||
// 不自动请求,保持与截图行为一致,点击搜索或回车触发
|
||||
})
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 这里先使用本地假数据占位,等后端接口确定后再切换为真实请求
|
||||
const mock = Array.from({ length: 8 }).map((_, i) => ({
|
||||
id: i + 1,
|
||||
stock_no: `HSAT-JN00${(i + 10).toString().padStart(2, '0')}`,
|
||||
order_no: 'VCS28762JN2',
|
||||
customer_name: 'Alicia',
|
||||
customer_source: '广交会',
|
||||
salesman: '王玉凯',
|
||||
date: '2025-08-27',
|
||||
remark: 'XXXXXXXXXXXX',
|
||||
status: 1,
|
||||
}))
|
||||
tableData.value = mock
|
||||
pagination.total = 24
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.pageSize = size
|
||||
getList()
|
||||
}
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.currentPage = page
|
||||
getList()
|
||||
}
|
||||
|
||||
const handleCreate = () => {
|
||||
// TODO: 跳转到创建备货单页面
|
||||
router.push('/crmpc/stocking/Add')
|
||||
}
|
||||
const handleView = (row: any) => {
|
||||
router.push('/crmpc/stocking/show')
|
||||
// TODO: 跳转或弹窗查看备货单
|
||||
}
|
||||
const handleView1 = (row: any) => {
|
||||
router.push('/crmpc/stocking/final_show')
|
||||
// TODO: 跳转或弹窗查看备货单
|
||||
}
|
||||
const handleCreateRepair = (row: any) => {
|
||||
router.push('/crmpc/stocking/final_add')
|
||||
// TODO: 跳转创建维修保单
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stocking-page {
|
||||
background: var(--art-main-bg-color);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.stocking-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 16px;
|
||||
background: var(--art-main-bg-color);
|
||||
}
|
||||
.toolbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.clickable { cursor: pointer; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user