产品信息的三张表适配手机端
This commit is contained in:
@@ -1,48 +1,67 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="100px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="上级编号" prop="parentId">
|
||||
<el-tree-select
|
||||
v-model="formData.parentId"
|
||||
:data="productCategoryTree"
|
||||
:props="defaultProps"
|
||||
check-strictly
|
||||
default-expand-all
|
||||
placeholder="请选择上级编号"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="编码" prop="code">
|
||||
<el-input v-model="formData.code" placeholder="请输入编码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input v-model="formData.sort" placeholder="请输入排序" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
<el-drawer
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
direction="rtl"
|
||||
size="100%"
|
||||
:close-on-press-escape="true"
|
||||
:destroy-on-close="true"
|
||||
:append-to-body="true"
|
||||
class="mobile-form-drawer"
|
||||
>
|
||||
<div class="mobile-form" v-loading="formLoading">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-position="top"
|
||||
>
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">基础信息</div>
|
||||
<el-form-item label="上级分类" prop="parentId">
|
||||
<el-tree-select
|
||||
v-model="formData.parentId"
|
||||
:data="productCategoryTree"
|
||||
:props="defaultProps"
|
||||
check-strictly
|
||||
default-expand-all
|
||||
placeholder="请选择上级分类"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入分类名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="分类编码" prop="code">
|
||||
<el-input v-model="formData.code" placeholder="请输入分类编码" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" placeholder="请输入排序" :precision="0" controls-position="right" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">状态信息</div>
|
||||
<el-form-item label="开启状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<div class="mobile-form__footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||
@@ -143,3 +162,54 @@ const getProductCategoryTree = async () => {
|
||||
productCategoryTree.value.push(root)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mobile-form {
|
||||
padding: 12px;
|
||||
}
|
||||
.mobile-form-section {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.mobile-form-section__title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.mobile-form__footer {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
padding: 12px 16px;
|
||||
padding-bottom: calc(12px + constant(safe-area-inset-bottom));
|
||||
padding-bottom: calc(12px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
margin: 0 -12px -12px;
|
||||
|
||||
.el-button {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
:deep(.el-input),
|
||||
:deep(.el-select),
|
||||
:deep(.el-input-number),
|
||||
:deep(.el-tree-select) {
|
||||
width: 100% !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,129 +1,83 @@
|
||||
<template>
|
||||
<doc-alert title="【产品】产品信息、分类、单位" url="https://doc.iocoder.cn/erp/product/" />
|
||||
<div class="mobile-product-category">
|
||||
<!-- 搜索操作栏 -->
|
||||
<div class="mobile-header">
|
||||
<div class="mobile-header__search">
|
||||
<el-input v-model="queryParams.name" placeholder="搜索分类名称" clearable @keyup.enter="handleQuery" :prefix-icon="Search" />
|
||||
</div>
|
||||
<div class="mobile-header__actions">
|
||||
<el-button :icon="Filter" circle @click="filterVisible = true" />
|
||||
<el-button type="primary" :icon="Plus" circle @click="openForm('create')" v-hasPermi="['erp:product-category:create']" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="分类名称" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="请输入分类名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="开启状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="请选择开启状态"
|
||||
clearable
|
||||
class="!w-240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="openForm('create')"
|
||||
v-hasPermi="['erp:product-category:create']"
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['erp:product-category:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
<el-button type="danger" plain @click="toggleExpandAll">
|
||||
<Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
<!-- 快捷操作 -->
|
||||
<div class="mobile-quick-actions">
|
||||
<el-button size="small" type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['erp:product-category:export']">导出</el-button>
|
||||
<el-button size="small" type="danger" plain @click="toggleExpandAll">{{ isExpandAll ? '折叠' : '展开' }}</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
:stripe="true"
|
||||
:show-overflow-tooltip="true"
|
||||
row-key="id"
|
||||
:default-expand-all="isExpandAll"
|
||||
v-if="refreshTable"
|
||||
@row-click="handleRowClick"
|
||||
>
|
||||
<el-table-column label="编码" align="center" prop="code" />
|
||||
<el-table-column label="名称" align="center" prop="name" />
|
||||
<el-table-column label="排序" align="center" prop="sort" />
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
align="center"
|
||||
prop="createTime"
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openForm('update', scope.row.id)"
|
||||
v-hasPermi="['erp:product-category:update']"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['erp:product-category:delete']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
<!-- 卡片列表 -->
|
||||
<div class="mobile-list" v-loading="loading">
|
||||
<div v-if="list.length === 0 && !loading" class="mobile-empty">
|
||||
<el-empty description="暂无产品分类" />
|
||||
</div>
|
||||
<div v-for="item in flatList" :key="item.id" class="mobile-card" @click="handleCardClick(item)" :style="{ marginLeft: (item.level || 0) * 12 + 'px' }">
|
||||
<div class="mobile-card__header">
|
||||
<span class="mobile-card__name">
|
||||
<span v-if="item.level > 0" class="mobile-card__indent">└─</span>
|
||||
{{ item.name || '-' }}
|
||||
</span>
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="item.status" />
|
||||
</div>
|
||||
<div class="mobile-card__body">
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">编码</span>
|
||||
<span class="mobile-card__value">{{ item.code || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">排序</span>
|
||||
<span class="mobile-card__value">{{ item.sort || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">创建时间</span>
|
||||
<span class="mobile-card__value">{{ formatDate(item.createTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card__footer">
|
||||
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:product-category:update']">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click.stop="handleDelete(item.id)" v-hasPermi="['erp:product-category:delete']">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<ProductCategoryForm ref="formRef" @success="getList" />
|
||||
<!-- 筛选抽屉 -->
|
||||
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="50%">
|
||||
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
|
||||
<el-form-item label="开启状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable style="width:100%">
|
||||
<el-option
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<ProductCategoryForm ref="formRef" @success="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Search, Filter, Plus } from '@element-plus/icons-vue'
|
||||
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { handleTree } from '@/utils/tree'
|
||||
@@ -139,6 +93,8 @@ const { t } = useI18n() // 国际化
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<ProductCategoryVO[]>([]) // 列表的数据
|
||||
const flatList = ref<ProductCategoryVO[]>([]) // 扁平化列表
|
||||
const filterVisible = ref(false) // 筛选抽屉
|
||||
const queryParams = reactive({
|
||||
name: undefined,
|
||||
status: undefined
|
||||
@@ -152,11 +108,27 @@ const getList = async () => {
|
||||
try {
|
||||
const data = await ProductCategoryApi.getProductCategoryList(queryParams)
|
||||
list.value = handleTree(data, 'id', 'parentId')
|
||||
flattenTree()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 扁平化树形结构 */
|
||||
const flattenTree = () => {
|
||||
const result: any[] = []
|
||||
const flatten = (nodes: any[], level = 0) => {
|
||||
nodes.forEach(node => {
|
||||
result.push({ ...node, level })
|
||||
if (node.children && node.children.length > 0 && isExpandAll.value) {
|
||||
flatten(node.children, level + 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
flatten(list.value)
|
||||
flatList.value = result
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
@@ -165,7 +137,13 @@ const handleQuery = () => {
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
queryFormRef.value?.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 筛选确认 */
|
||||
const handleFilterConfirm = () => {
|
||||
filterVisible.value = false
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
@@ -175,10 +153,16 @@ const openForm = (type: string, id?: number) => {
|
||||
formRef.value.open(type, id)
|
||||
}
|
||||
|
||||
/** 行点击操作 */
|
||||
const handleRowClick = (row: ProductCategoryVO) => {
|
||||
/** 卡片点击 */
|
||||
const handleCardClick = (row: ProductCategoryVO) => {
|
||||
openForm('update', row.id)
|
||||
}
|
||||
|
||||
/** 格式化日期 */
|
||||
const formatDate = (date: any) => {
|
||||
if (!date) return '-'
|
||||
return dateFormatter({ cellValue: date })
|
||||
}
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
@@ -209,12 +193,9 @@ const handleExport = async () => {
|
||||
|
||||
/** 展开/折叠操作 */
|
||||
const isExpandAll = ref(true) // 是否展开,默认全部展开
|
||||
const refreshTable = ref(true) // 重新渲染表格状态
|
||||
const toggleExpandAll = async () => {
|
||||
refreshTable.value = false
|
||||
const toggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value
|
||||
await nextTick()
|
||||
refreshTable.value = true
|
||||
flattenTree()
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
@@ -222,3 +203,32 @@ onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mobile-product-category {
|
||||
padding: 12px;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.mobile-header {
|
||||
display: flex; gap: 8px; align-items: center; margin-bottom: 12px;
|
||||
&__search { flex: 1; }
|
||||
&__actions { display: flex; gap: 4px; flex-shrink: 0; }
|
||||
}
|
||||
.mobile-quick-actions {
|
||||
display: flex; gap: 8px; margin-bottom: 12px;
|
||||
}
|
||||
.mobile-list { display: flex; flex-direction: column; gap: 10px; }
|
||||
.mobile-empty { padding: 40px 0; }
|
||||
.mobile-card {
|
||||
background: #fff; border-radius: 10px; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
||||
&__header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
||||
&__name { font-weight: 600; font-size: 15px; color: #303133; }
|
||||
&__indent { color: #909399; margin-right: 4px; }
|
||||
&__body { font-size: 13px; }
|
||||
&__row { display: flex; justify-content: space-between; padding: 3px 0; }
|
||||
&__label { color: #909399; flex-shrink: 0; margin-right: 12px; }
|
||||
&__value { color: #606266; text-align: right; }
|
||||
&__footer { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; padding-top: 10px; border-top: 1px solid #f0f0f0; }
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,40 +1,41 @@
|
||||
<!-- ERP 产品的新增/修改 -->
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="100px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入名称" />
|
||||
<el-drawer
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
direction="rtl"
|
||||
size="100%"
|
||||
:close-on-press-escape="true"
|
||||
:destroy-on-close="true"
|
||||
:append-to-body="true"
|
||||
class="mobile-form-drawer"
|
||||
>
|
||||
<div class="mobile-form" v-loading="formLoading">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-position="top"
|
||||
>
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">基础信息</div>
|
||||
<el-form-item label="产品名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入产品名称" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="条码" prop="barCode">
|
||||
<el-input v-model="formData.barCode" placeholder="请输入条码" />
|
||||
<el-form-item label="产品条码" prop="barCode">
|
||||
<el-input v-model="formData.barCode" placeholder="请输入产品条码" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="分类" prop="categoryId">
|
||||
<el-form-item label="产品分类" prop="categoryId">
|
||||
<el-tree-select
|
||||
v-model="formData.categoryId"
|
||||
:data="categoryList"
|
||||
:props="defaultProps"
|
||||
check-strictly
|
||||
default-expand-all
|
||||
placeholder="请选择分类"
|
||||
class="w-1/1"
|
||||
placeholder="请选择产品分类"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单位" prop="unitId">
|
||||
<el-select v-model="formData.unitId" clearable placeholder="请选择单位" class="w-1/1">
|
||||
<el-form-item label="产品单位" prop="unitId">
|
||||
<el-select v-model="formData.unitId" clearable placeholder="请选择产品单位">
|
||||
<el-option
|
||||
v-for="unit in unitList"
|
||||
:key="unit.id"
|
||||
@@ -43,9 +44,96 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-form-item label="产品规格" prop="standard">
|
||||
<el-input v-model="formData.standard" placeholder="请输入产品规格" clearable />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">价格信息</div>
|
||||
<el-form-item label="采购价格(元)" prop="purchasePrice">
|
||||
<el-input-number
|
||||
v-model="formData.purchasePrice"
|
||||
placeholder="请输入采购价格"
|
||||
:min="0"
|
||||
:precision="4"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="销售价格(元)" prop="salePrice">
|
||||
<el-input-number
|
||||
v-model="formData.salePrice"
|
||||
placeholder="请输入销售价格"
|
||||
:min="0"
|
||||
:precision="4"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="货值(元)" prop="minPrice">
|
||||
<el-input-number
|
||||
v-model="formData.minPrice"
|
||||
placeholder="请输入最低价格"
|
||||
:min="0"
|
||||
:precision="4"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">库存信息</div>
|
||||
<el-form-item label="库存预警数量" prop="stockAlertCount">
|
||||
<el-input-number
|
||||
v-model="formData.stockAlertCount"
|
||||
placeholder="请输入库存预警数量"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="保质期天数" prop="expiryDay">
|
||||
<el-input-number
|
||||
v-model="formData.expiryDay"
|
||||
placeholder="请输入保质期天数"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="重量(kg)" prop="weight">
|
||||
<el-input-number
|
||||
v-model="formData.weight"
|
||||
placeholder="请输入重量"
|
||||
:min="0"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">供应商信息</div>
|
||||
<el-form-item label="供应商" prop="supplierId">
|
||||
<el-select v-model="formData.supplierId" clearable filterable placeholder="请选择供应商">
|
||||
<el-option
|
||||
v-for="item in supplierList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">其他信息</div>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" :rows="3" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">状态信息</div>
|
||||
<el-form-item label="开启状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
@@ -56,101 +144,16 @@
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规格" prop="standard">
|
||||
<el-input v-model="formData.standard" placeholder="请输入规格" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="保质期天数" prop="expiryDay">
|
||||
<el-input-number
|
||||
v-model="formData.expiryDay"
|
||||
placeholder="请输入保质期天数"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
class="!w-1/1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="重量(kg)" prop="weight">
|
||||
<el-input-number
|
||||
v-model="formData.weight"
|
||||
placeholder="请输入重量(kg)"
|
||||
:min="0"
|
||||
class="!w-1/1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采购价格" prop="purchasePrice">
|
||||
<el-input-number
|
||||
v-model="formData.purchasePrice"
|
||||
placeholder="请输入采购价格,单位:元"
|
||||
:min="0"
|
||||
:precision="4"
|
||||
class="!w-1/1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="销售价格" prop="salePrice">
|
||||
<el-input-number
|
||||
v-model="formData.salePrice"
|
||||
placeholder="请输入销售价格,单位:元"
|
||||
:min="0"
|
||||
:precision="4"
|
||||
class="!w-1/1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="货值" prop="minPrice">
|
||||
<el-input-number
|
||||
v-model="formData.minPrice"
|
||||
placeholder="请输入最低价格,单位:元"
|
||||
:min="0"
|
||||
:precision="4"
|
||||
class="!w-1/1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="库存预警" prop="stockAlertCount">
|
||||
<el-input-number
|
||||
v-model="formData.stockAlertCount"
|
||||
placeholder="请输入库存预警数量"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
class="!w-1/1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="供应商" prop="supplierId">
|
||||
<el-select v-model="formData.supplierId" clearable filterable placeholder="请选择供应商" class="w-1/1">
|
||||
<el-option
|
||||
v-for="item in supplierList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<div class="mobile-form__footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ProductApi, ProductVO } from '@/api/erp/product/product'
|
||||
@@ -269,3 +272,54 @@ const resetForm = () => {
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mobile-form {
|
||||
padding: 12px;
|
||||
}
|
||||
.mobile-form-section {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.mobile-form-section__title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.mobile-form__footer {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
padding: 12px 16px;
|
||||
padding-bottom: calc(12px + constant(safe-area-inset-bottom));
|
||||
padding-bottom: calc(12px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
margin: 0 -12px -12px;
|
||||
|
||||
.el-button {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
:deep(.el-input),
|
||||
:deep(.el-select),
|
||||
:deep(.el-input-number),
|
||||
:deep(.el-tree-select) {
|
||||
width: 100% !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,138 +1,97 @@
|
||||
<!-- ERP 产品列表 -->
|
||||
<template>
|
||||
<doc-alert title="【产品】产品信息、分类、单位" url="https://doc.iocoder.cn/erp/product/" />
|
||||
<div class="mobile-product">
|
||||
<!-- 搜索操作栏 -->
|
||||
<div class="mobile-header">
|
||||
<div class="mobile-header__search">
|
||||
<el-input v-model="queryParams.name" placeholder="搜索产品名称" clearable @keyup.enter="handleQuery" :prefix-icon="Search" />
|
||||
</div>
|
||||
<div class="mobile-header__actions">
|
||||
<el-button :icon="Filter" circle @click="filterVisible = true" />
|
||||
<el-button type="primary" :icon="Plus" circle @click="openForm('create')" v-hasPermi="['erp:product:create']" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="请输入名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类" prop="categoryId">
|
||||
<el-tree-select
|
||||
v-model="queryParams.categoryId"
|
||||
:data="categoryList"
|
||||
:props="defaultProps"
|
||||
check-strictly
|
||||
default-expand-all
|
||||
placeholder="请输入分类"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="openForm('create')"
|
||||
v-hasPermi="['erp:product:create']"
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['erp:product:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
<!-- 快捷操作 -->
|
||||
<div class="mobile-quick-actions">
|
||||
<el-button size="small" type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['erp:product:export']">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 卡片列表 -->
|
||||
<div class="mobile-list" v-loading="loading">
|
||||
<div v-if="list.length === 0 && !loading" class="mobile-empty">
|
||||
<el-empty description="暂无产品" />
|
||||
</div>
|
||||
<div v-for="item in list" :key="item.id" class="mobile-card" @click="handleCardClick(item)">
|
||||
<div class="mobile-card__header">
|
||||
<span class="mobile-card__name">{{ item.name || '-' }}</span>
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="item.status" />
|
||||
</div>
|
||||
<div class="mobile-card__body">
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">条码</span>
|
||||
<span class="mobile-card__value">{{ item.barCode || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">规格</span>
|
||||
<span class="mobile-card__value">{{ item.standard || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">分类</span>
|
||||
<span class="mobile-card__value">{{ item.categoryName || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">单位</span>
|
||||
<span class="mobile-card__value">{{ item.unitName || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">供应商</span>
|
||||
<span class="mobile-card__value">{{ item.supplierName || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">货值</span>
|
||||
<span class="mobile-card__value">{{ formatPrice(item.minPrice) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card__footer">
|
||||
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:product:update']" :disabled="item.name === '番茄' || item.name === '甜菊糖' || item.name === '番茄酱' || item.name === '甜叶菊'">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click.stop="handleDelete(item.id)" v-hasPermi="['erp:product:delete']" :disabled="item.name === '番茄' || item.name === '甜菊糖' || item.name === '番茄酱' || item.name === '甜叶菊'">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" @row-click="handleRowClick">
|
||||
<el-table-column label="条码" align="center" prop="barCode" />
|
||||
<el-table-column label="名称" align="center" prop="name" />
|
||||
<el-table-column label="规格" align="center" prop="standard" />
|
||||
<el-table-column label="分类" align="center" prop="categoryName" />
|
||||
<el-table-column label="单位" align="center" prop="unitName" />
|
||||
<el-table-column label="供应商" align="center" prop="supplierName" />
|
||||
<!-- <el-table-column-->
|
||||
<!-- label="采购价格"-->
|
||||
<!-- align="center"-->
|
||||
<!-- prop="purchasePrice"-->
|
||||
<!-- :formatter="erpPriceTableColumnFormatter"-->
|
||||
<!-- />-->
|
||||
<!-- <el-table-column-->
|
||||
<!-- label="销售价格"-->
|
||||
<!-- align="center"-->
|
||||
<!-- prop="salePrice"-->
|
||||
<!-- :formatter="erpPriceTableColumnFormatter"-->
|
||||
<!-- />-->
|
||||
<el-table-column
|
||||
label="货值"
|
||||
align="center"
|
||||
prop="minPrice"
|
||||
:formatter="erpPriceTableColumnFormatter"
|
||||
/>
|
||||
<el-table-column label="库存预警" align="center" prop="stockAlertCount" />
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
align="center"
|
||||
prop="createTime"
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column label="操作" align="center" width="110">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openForm('update', scope.row.id)"
|
||||
v-hasPermi="['erp:product:update']"
|
||||
:disabled="scope.row.name === '番茄' || scope.row.name === '甜菊糖' || scope.row.name === '番茄酱' ||scope.row.name === '甜叶菊'"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['erp:product:delete']"
|
||||
:disabled="scope.row.name === '番茄' || scope.row.name === '甜菊糖' || scope.row.name === '番茄酱' ||scope.row.name === '甜叶菊'"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
<div class="mobile-pagination" v-if="total > 0">
|
||||
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" :page-sizes="[10, 20]" layout="total, prev, pager, next" :pager-count="5" @pagination="getList" />
|
||||
</div>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<ProductForm ref="formRef" @success="getList" />
|
||||
<!-- 筛选抽屉 -->
|
||||
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="50%">
|
||||
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
|
||||
<el-form-item label="产品分类" prop="categoryId">
|
||||
<el-tree-select
|
||||
v-model="queryParams.categoryId"
|
||||
:data="categoryList"
|
||||
:props="defaultProps"
|
||||
check-strictly
|
||||
default-expand-all
|
||||
placeholder="请选择分类"
|
||||
style="width:100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<ProductForm ref="formRef" @success="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Search, Filter, Plus } from '@element-plus/icons-vue'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import { ProductApi, ProductVO } from '@/api/erp/product/product'
|
||||
@@ -151,6 +110,7 @@ const { t } = useI18n() // 国际化
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<ProductVO[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
const filterVisible = ref(false) // 筛选抽屉
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
@@ -181,16 +141,26 @@ const handleQuery = () => {
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
queryFormRef.value?.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
/** 行点击操作 */
|
||||
const handleRowClick = (row: ProductVO) => {
|
||||
if (row.name === '番茄' || row.name === '甜菊糖' || row.name === '番茄酱' || row.name === '甜叶菊'){
|
||||
return;
|
||||
}else {
|
||||
openForm('update', row.id)
|
||||
}
|
||||
|
||||
/** 筛选确认 */
|
||||
const handleFilterConfirm = () => {
|
||||
filterVisible.value = false
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 卡片点击 */
|
||||
const handleCardClick = (row: ProductVO) => {
|
||||
if (row.name === '番茄' || row.name === '甜菊糖' || row.name === '番茄酱' || row.name === '甜叶菊') return
|
||||
openForm('update', row.id)
|
||||
}
|
||||
|
||||
/** 格式化价格 */
|
||||
const formatPrice = (price: any) => {
|
||||
if (!price) return '-'
|
||||
return erpPriceTableColumnFormatter({ cellValue: price })
|
||||
}
|
||||
/** 添加/修改操作 */
|
||||
const formRef = ref()
|
||||
@@ -234,3 +204,35 @@ onMounted(async () => {
|
||||
categoryList.value = handleTree(categoryData, 'id', 'parentId')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mobile-product {
|
||||
padding: 12px;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.mobile-header {
|
||||
display: flex; gap: 8px; align-items: center; margin-bottom: 12px;
|
||||
&__search { flex: 1; }
|
||||
&__actions { display: flex; gap: 4px; flex-shrink: 0; }
|
||||
}
|
||||
.mobile-quick-actions {
|
||||
display: flex; gap: 8px; margin-bottom: 12px;
|
||||
}
|
||||
.mobile-list { display: flex; flex-direction: column; gap: 10px; }
|
||||
.mobile-empty { padding: 40px 0; }
|
||||
.mobile-card {
|
||||
background: #fff; border-radius: 10px; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
||||
&__header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
||||
&__name { font-weight: 600; font-size: 15px; color: #303133; }
|
||||
&__body { font-size: 13px; }
|
||||
&__row { display: flex; justify-content: space-between; padding: 3px 0; }
|
||||
&__label { color: #909399; flex-shrink: 0; margin-right: 12px; }
|
||||
&__value { color: #606266; text-align: right; }
|
||||
&__footer { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; padding-top: 10px; border-top: 1px solid #f0f0f0; }
|
||||
}
|
||||
.mobile-pagination {
|
||||
margin-top: 12px; display: flex; justify-content: center;
|
||||
:deep(.el-pagination) { flex-wrap: wrap; justify-content: center; }
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,32 +1,51 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="100px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="单位名字" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入单位名字" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单位状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
<el-drawer
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
direction="rtl"
|
||||
size="100%"
|
||||
:close-on-press-escape="true"
|
||||
:destroy-on-close="true"
|
||||
:append-to-body="true"
|
||||
class="mobile-form-drawer"
|
||||
>
|
||||
<div class="mobile-form" v-loading="formLoading">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-position="top"
|
||||
>
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">基础信息</div>
|
||||
<el-form-item label="单位名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入单位名称" clearable />
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="mobile-form-section">
|
||||
<div class="mobile-form-section__title">状态信息</div>
|
||||
<el-form-item label="开启状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<div class="mobile-form__footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ProductUnitApi } from '@/api/erp/product/unit'
|
||||
@@ -106,3 +125,52 @@ const resetForm = () => {
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mobile-form {
|
||||
padding: 12px;
|
||||
}
|
||||
.mobile-form-section {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.mobile-form-section__title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.mobile-form__footer {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
padding: 12px 16px;
|
||||
padding-bottom: calc(12px + constant(safe-area-inset-bottom));
|
||||
padding-bottom: calc(12px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
z-index: 10;
|
||||
margin: 0 -12px -12px;
|
||||
|
||||
.el-button {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
:deep(.el-input),
|
||||
:deep(.el-select) {
|
||||
width: 100% !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,115 +1,76 @@
|
||||
<template>
|
||||
<doc-alert title="【产品】产品信息、分类、单位" url="https://doc.iocoder.cn/erp/product/" />
|
||||
<div class="mobile-product-unit">
|
||||
<!-- 搜索操作栏 -->
|
||||
<div class="mobile-header">
|
||||
<div class="mobile-header__search">
|
||||
<el-input v-model="queryParams.name" placeholder="搜索单位名称" clearable @keyup.enter="handleQuery" :prefix-icon="Search" />
|
||||
</div>
|
||||
<div class="mobile-header__actions">
|
||||
<el-button :icon="Filter" circle @click="filterVisible = true" />
|
||||
<el-button type="primary" :icon="Plus" circle @click="openForm('create')" v-hasPermi="['erp:product-unit:create']" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ContentWrap>
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="单位名字" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="请输入单位名字"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="单位状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="请选择单位状态"
|
||||
clearable
|
||||
class="!w-240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="openForm('create')"
|
||||
v-hasPermi="['erp:product-unit:create']"
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['erp:product-unit:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
<!-- 快捷操作 -->
|
||||
<div class="mobile-quick-actions">
|
||||
<el-button size="small" type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['erp:product-unit:export']">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 卡片列表 -->
|
||||
<div class="mobile-list" v-loading="loading">
|
||||
<div v-if="list.length === 0 && !loading" class="mobile-empty">
|
||||
<el-empty description="暂无产品单位" />
|
||||
</div>
|
||||
<div v-for="item in list" :key="item.id" class="mobile-card" @click="handleCardClick(item)">
|
||||
<div class="mobile-card__header">
|
||||
<span class="mobile-card__name">{{ item.name || '-' }}</span>
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="item.status" />
|
||||
</div>
|
||||
<div class="mobile-card__body">
|
||||
<div class="mobile-card__row">
|
||||
<span class="mobile-card__label">创建时间</span>
|
||||
<span class="mobile-card__value">{{ formatDate(item.createTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card__footer">
|
||||
<el-button size="small" type="primary" @click.stop="openForm('update', item.id)" v-hasPermi="['erp:product-unit:update']">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click.stop="handleDelete(item.id)" v-hasPermi="['erp:product-unit:delete']">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" @row-click="handleRowClick">
|
||||
<el-table-column label="名字" align="center" prop="name" />
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="创建时间"
|
||||
align="center"
|
||||
prop="createTime"
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openForm('update', scope.row.id)"
|
||||
v-hasPermi="['erp:product-unit:update']"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['erp:product-unit:delete']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
<div class="mobile-pagination" v-if="total > 0">
|
||||
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" :page-sizes="[10, 20]" layout="total, prev, pager, next" :pager-count="5" @pagination="getList" />
|
||||
</div>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<ProductUnitForm ref="formRef" @success="getList" />
|
||||
<!-- 筛选抽屉 -->
|
||||
<el-drawer v-model="filterVisible" title="筛选条件" direction="btt" size="50%">
|
||||
<el-form :model="queryParams" ref="queryFormRef" label-position="top">
|
||||
<el-form-item label="单位状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择单位状态" clearable style="width:100%">
|
||||
<el-option
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button type="primary" @click="handleFilterConfirm">确认筛选</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<ProductUnitForm ref="formRef" @success="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Search, Filter, Plus } from '@element-plus/icons-vue'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import { ProductUnitApi, ProductUnitVO } from '@/api/erp/product/unit'
|
||||
@@ -125,6 +86,7 @@ const { t } = useI18n() // 国际化
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<ProductUnitVO[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
const filterVisible = ref(false) // 筛选抽屉
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
@@ -154,7 +116,13 @@ const handleQuery = () => {
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
queryFormRef.value?.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 筛选确认 */
|
||||
const handleFilterConfirm = () => {
|
||||
filterVisible.value = false
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
@@ -177,11 +145,17 @@ const handleDelete = async (id: number) => {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 行点击操作 */
|
||||
const handleRowClick = (row: ProductUnitVO) => {
|
||||
/** 卡片点击 */
|
||||
const handleCardClick = (row: ProductUnitVO) => {
|
||||
openForm('update', row.id)
|
||||
}
|
||||
|
||||
/** 格式化日期 */
|
||||
const formatDate = (date: any) => {
|
||||
if (!date) return '-'
|
||||
return dateFormatter({ cellValue: date })
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
@@ -202,3 +176,35 @@ onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mobile-product-unit {
|
||||
padding: 12px;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.mobile-header {
|
||||
display: flex; gap: 8px; align-items: center; margin-bottom: 12px;
|
||||
&__search { flex: 1; }
|
||||
&__actions { display: flex; gap: 4px; flex-shrink: 0; }
|
||||
}
|
||||
.mobile-quick-actions {
|
||||
display: flex; gap: 8px; margin-bottom: 12px;
|
||||
}
|
||||
.mobile-list { display: flex; flex-direction: column; gap: 10px; }
|
||||
.mobile-empty { padding: 40px 0; }
|
||||
.mobile-card {
|
||||
background: #fff; border-radius: 10px; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
||||
&__header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
||||
&__name { font-weight: 600; font-size: 15px; color: #303133; }
|
||||
&__body { font-size: 13px; }
|
||||
&__row { display: flex; justify-content: space-between; padding: 3px 0; }
|
||||
&__label { color: #909399; flex-shrink: 0; margin-right: 12px; }
|
||||
&__value { color: #606266; text-align: right; }
|
||||
&__footer { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; padding-top: 10px; border-top: 1px solid #f0f0f0; }
|
||||
}
|
||||
.mobile-pagination {
|
||||
margin-top: 12px; display: flex; justify-content: center;
|
||||
:deep(.el-pagination) { flex-wrap: wrap; justify-content: center; }
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user