车辆信息,备货单 等页面
This commit is contained in:
@@ -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
Reference in New Issue
Block a user