基础设置主要分为以下几个模块:
对于商品就要说下SPU和 SKU
iPhone XS
iPhone XS 金色 64g
1、主页面代码
<template>
<div class="container">
<div>
<!-- Main Content -->
<v-card class="mt-5">
<v-card-text>
<div class="operateArea">
<v-row no-gutters>
<!-- Operate Btn -->
<v-col cols="12" sm="3" class="col">
<tooltip-btn icon="mdi-plus" :tooltip-text="$t('system.page.add')" @click="method.add()"></tooltip-btn>
<tooltip-btn icon="mdi-refresh" :tooltip-text="$t('system.page.refresh')" @click="method.refresh()"></tooltip-btn>
<tooltip-btn icon="mdi-export-variant" :tooltip-text="$t('system.page.export')" @click="method.exportTable"></tooltip-btn>
</v-col>
<!-- Search Input -->
<v-col cols="12" sm="9">
<v-row no-gutters @keyup.enter="method.sureSearch">
<v-col cols="4">
<v-text-field
v-model="data.searchForm.spu_code"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.commodityManagement.spu_code')"
variant="solo"
>
</v-text-field>
</v-col>
<v-col cols="4">
<v-text-field
v-model="data.searchForm.spu_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.commodityManagement.spu_name')"
variant="solo"
>
</v-text-field>
</v-col>
<v-col cols="4">
<v-text-field
v-model="data.searchForm.category_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.commodityManagement.category_name')"
variant="solo"
>
</v-text-field>
</v-col>
</v-row>
</v-col>
</v-row>
</div>
<!-- Table -->
<div
class="mt-5"
:style="{
height: cardHeight
}"
>
<vxe-table
ref="xTable"
:data="data.tableData"
:column-config="{
minWidth: '100px'
}"
:height="tableHeight"
align="center"
:tree-config="data.tableTreeConfig"
>
<template #empty>
{{ i18n.global.t('system.page.noData') }}
</template>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="spu_code" width="150px" :title="$t('base.commodityManagement.spu_code')" tree-node>
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.sku_code }}</span>
<span v-else>{{ row.spu_code }}</span>
</template>
</vxe-column>
<vxe-column field="spu_name" :title="$t('base.commodityManagement.spu_name')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.sku_name }}</span>
<span v-else>{{ row.spu_name }}</span>
</template>
</vxe-column>
<vxe-column field="category_name" :title="$t('base.commodityManagement.category_name')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.unit }}</span>
<span v-else>{{ row.category_name }}</span>
</template>
</vxe-column>
<vxe-column field="spu_description" :title="$t('base.commodityManagement.spu_description')"> </vxe-column>
<vxe-column field="bar_code" :title="$t('base.commodityManagement.bar_code')"> </vxe-column>
<vxe-column field="supplier_name" :title="$t('base.commodityManagement.supplier_name')"> </vxe-column>
<vxe-column field="brand" :title="$t('base.commodityManagement.brand')"> </vxe-column>
<vxe-column field="weight" :title="$t('base.commodityManagement.weight')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.weight} ${GetUnit('weight', row.weight_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="lenght" :title="$t('base.commodityManagement.lenght')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.lenght} ${GetUnit('length', row.length_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="width" :title="$t('base.commodityManagement.width')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.width} ${GetUnit('length', row.length_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="height" :title="$t('base.commodityManagement.height')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.height} ${GetUnit('length', row.length_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="volume" :title="$t('base.commodityManagement.volume')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.volume} ${GetUnit('volume', row.volume_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="cost" :title="$t('base.commodityManagement.cost')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.cost }}</span>
</template>
</vxe-column>
<vxe-column field="price" :title="$t('base.commodityManagement.price')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.price }}</span>
</template>
</vxe-column>
<!-- <vxe-column field="sku_name" :title="$t('base.commodityManagement.sku_name')"></vxe-column> -->
<!-- <vxe-column field="supplier_name" :title="$t('base.commodityManagement.supplier_name')"></vxe-column>
<vxe-column field="brand" :title="$t('base.commodityManagement.brand')"></vxe-column>
<vxe-column field="unit" :title="$t('base.commodityManagement.unit')"></vxe-column>
<vxe-column field="cost" :title="$t('base.commodityManagement.cost')"></vxe-column> -->
<vxe-column field="operate" :title="$t('system.page.operate')" width="160" :resizable="false" show-overflow>
<template #default="{ row }">
<div v-if="!row.parent_id || row.parent_id <= 0">
<tooltip-btn
:flat="true"
icon="mdi-pencil-outline"
:tooltip-text="$t('system.page.edit')"
@click="method.editRow(row)"
></tooltip-btn>
<tooltip-btn
:flat="true"
icon="mdi-delete-outline"
:tooltip-text="$t('system.page.delete')"
:icon-color="errorColor"
@click="method.deleteRow(row)"
></tooltip-btn>
</div>
</template>
</vxe-column>
</vxe-table>
<custom-pager
:current-page="data.tablePage.pageIndex"
:page-size="data.tablePage.pageSize"
perfect
:total="data.tablePage.total"
:page-sizes="PAGE_SIZE"
:layouts="PAGE_LAYOUT"
@page-change="method.handlePageChange"
>
</custom-pager>
</div>
</v-card-text>
</v-card>
</div>
<!-- Add or modify data mode window -->
<addOrUpdateDialog :show-dialog="data.showDialog" :form="data.dialogForm" @close="method.closeDialog" @saveSuccess="method.saveSuccess" />
</div>
</template>
<script lang="ts" setup>
import { computed, reactive, onMounted, ref, watch } from 'vue'
import { VxePagerEvents } from 'vxe-table'
import { computedCardHeight, computedTableHeight, errorColor } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { CommodityVO, DataProps } from '@/types/Base/CommodityManagement'
import { getSpuList, deleteSpu } from '@/api/base/commodityManagementSetting'
import { hookComponent } from '@/components/system'
import addOrUpdateDialog from './add-or-update-commodity.vue'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import i18n from '@/languages/i18n'
import { GetUnit } from '@/constant/commodityManagement'
import customPager from '@/components/custom-pager.vue'
import { setSearchObject } from '@/utils/common'
import { exportData } from '@/utils/exportTable'
import { DEBOUNCE_TIME } from '@/constant/system'
const xTable = ref()
const data: DataProps = reactive({
searchForm: {
spu_code: '',
spu_name: '',
category_name: ''
},
timer: null,
tableData: [],
tablePage: {
total: 0,
pageIndex: 1,
pageSize: DEFAULT_PAGE_SIZE
},
tableTreeConfig: {
transform: true,
rowField: 'tree_id',
parentField: 'parent_id'
},
// Dialog info
showDialog: false,
dialogForm: {
id: 0,
spu_code: '',
spu_name: '',
category_id: 0,
category_name: '',
spu_description: '',
bar_code: '',
supplier_id: 0,
supplier_name: '',
brand: '',
origin: '',
length_unit: 1,
volume_unit: 0,
weight_unit: 1,
detailList: []
}
})
const method = reactive({
sureSearch: () => {
data.tablePage.searchObjects = setSearchObject(data.searchForm)
method.getCompanyList()
},
// Find Data by Pagination
getCompanyList: async () => {
const { data: res } = await getSpuList(data.tablePage)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.tableData = []
for (const item of res.data.rows) {
item.tree_id = item.id
data.tableData.push(item)
for (const ditem of item.detailList) {
ditem.tree_id = 0
ditem.parent_id = item.id
ditem.length_unit = item.length_unit
ditem.volume_unit = item.volume_unit
ditem.weight_unit = item.weight_unit
data.tableData.push(ditem)
}
}
data.tablePage.total = res.data.totals
},
// Add user
add: () => {
data.dialogForm = {
id: 0,
spu_code: '',
spu_name: '',
spu_description: '',
bar_code: '',
brand: '',
length_unit: 1,
volume_unit: 0,
weight_unit: 1,
detailList: []
}
data.showDialog = true
},
// Shut add or update dialog
closeDialog: () => {
data.showDialog = false
},
// after Add or update success.
saveSuccess: () => {
method.refresh()
method.closeDialog()
},
// Refresh data
refresh: () => {
method.getCompanyList()
},
editRow(row: CommodityVO) {
data.dialogForm = JSON.parse(JSON.stringify(row))
data.showDialog = true
},
deleteRow(row: CommodityVO) {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteMessage'),
handleConfirm: async () => {
if (row.id) {
const { data: res } = await deleteSpu(row.id)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.delete') }${ i18n.global.t('system.tips.success') }`
})
method.refresh()
}
}
})
},
// Export table
exportTable: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.commodityManagement'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
// When change paging
handlePageChange: ref<VxePagerEvents.PageChange>(({ currentPage, pageSize }) => {
data.tablePage.pageIndex = currentPage
data.tablePage.pageSize = pageSize
method.refresh()
})
})
onMounted(async () => {
await method.getCompanyList()
})
const cardHeight = computed(() => computedCardHeight({ hasTab: false }))
const tableHeight = computed(() => computedTableHeight({ hasTab: false }))
watch(
() => data.searchForm,
() => {
// debounce
if (data.timer) {
clearTimeout(data.timer)
}
data.timer = setTimeout(() => {
data.timer = null
method.sureSearch()
}, DEBOUNCE_TIME)
},
{
deep: true
}
)
</script>
<style scoped lang="less">
.operateArea {
width: 100%;
min-width: 760px;
display: flex;
align-items: center;
border-radius: 10px;
padding: 0 10px;
}
.col {
display: flex;
align-items: center;
}
</style>
2、窗体代码
<template>
<v-dialog v-model="isShow" width="70%" transition="dialog-top-transition" :persistent="true">
<template #default>
<v-card>
<v-toolbar color="white" :title="`${$t('router.sideBar.commodityManagement')}`"></v-toolbar>
<v-card-text>
<v-row>
<v-col cols="3">
<div class="mainForm" :style="{ height: mainFormHeight }">
<v-form ref="formRef">
<v-text-field
v-model="data.form.spu_code"
:rules="data.rules.spu_code"
:label="$t('base.commodityManagement.spu_code')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-text-field
v-model="data.form.spu_name"
:rules="data.rules.spu_name"
:label="$t('base.commodityManagement.spu_name')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-select
v-model="data.form.category_name"
:items="data.combobox.category_name"
item-title="label"
item-value="label"
:rules="data.rules.category_name"
:label="$t('base.commodityManagement.category_name')"
variant="outlined"
density="compact"
class="mb-4"
clearable
@update:model-value="method.categoryNameChange"
></v-select>
<v-text-field
v-model="data.form.spu_description"
:rules="data.rules.spu_description"
:label="$t('base.commodityManagement.spu_description')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-text-field
v-model="data.form.bar_code"
:rules="data.rules.bar_code"
:label="$t('base.commodityManagement.bar_code')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-select
v-model="data.form.supplier_name"
:items="data.combobox.supplier_name"
:rules="data.rules.supplier_name"
item-title="label"
item-value="label"
:label="$t('base.commodityManagement.supplier_name')"
variant="outlined"
density="compact"
class="mb-4"
clearable
@update:model-value="method.supplierNameChange"
></v-select>
<v-text-field
v-model="data.form.brand"
:rules="data.rules.brand"
:label="$t('base.commodityManagement.brand')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-select
v-model="data.form.length_unit"
:items="data.combobox.length_unit"
item-title="label"
item-value="value"
:rules="data.rules.length_unit"
:label="$t('base.commodityManagement.length_unit')"
variant="outlined"
density="compact"
class="mb-4"
clearable
></v-select>
<v-select
v-model="data.form.volume_unit"
:items="data.combobox.volume_unit"
item-title="label"
item-value="value"
:rules="data.rules.volume_unit"
:label="$t('base.commodityManagement.volume_unit')"
variant="outlined"
density="compact"
class="mb-4"
clearable
></v-select>
<v-select
v-model="data.form.weight_unit"
:items="data.combobox.weight_unit"
item-title="label"
item-value="value"
:rules="data.rules.weight_unit"
:label="$t('base.commodityManagement.weight_unit')"
variant="outlined"
density="compact"
class="mb-4"
clearable
></v-select>
</v-form>
</div>
</v-col>
<v-col cols="9">
<div class="dataTable">
<div class="toolbar">
<tooltip-btn
icon="mdi-plus"
:tooltip-text="$t('system.page.insertOneRow')"
size="x-small"
@click="method.insertOneRow"
></tooltip-btn>
<tooltip-btn
icon="mdi-export-variant"
:tooltip-text="$t('system.page.export')"
size="x-small"
@click="method.exportTable"
></tooltip-btn>
</div>
<vxe-table
ref="xTable"
keep-source
:column-config="{ minWidth: '100px' }"
:data="data.form.detailList"
:height="SYSTEM_HEIGHT.SELECT_TABLE"
align="center"
:edit-rules="data.validRules"
:edit-config="{ trigger: 'click', mode: 'cell' }"
:mouse-config="{ selected: true }"
:keyboard-config="{ isArrow: true, isDel: true, isEnter: true, isTab: true, isEdit: true, isChecked: true }"
>
<template #empty>
{{ i18n.global.t('system.page.noData') }}
</template>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="sku_code" :title="$t('base.commodityManagement.sku_code')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.sku_code" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="sku_name" :title="$t('base.commodityManagement.sku_name')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.sku_name" type="text"></vxe-input>
</template>
</vxe-column>
<!-- <vxe-column field="supplier_name" :title="$t('base.commodityManagement.supplier_name')"></vxe-column> -->
<!-- <vxe-column field="brand" :title="$t('base.commodityManagement.brand')"></vxe-column> -->
<vxe-column field="unit" :title="$t('base.commodityManagement.unit')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.unit" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="weight" :title="$t('base.commodityManagement.weight')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.weight" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="lenght" :title="$t('base.commodityManagement.lenght')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.lenght" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="width" :title="$t('base.commodityManagement.width')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.width" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="height" :title="$t('base.commodityManagement.height')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.height" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="volume" :title="$t('base.commodityManagement.volume')"> </vxe-column>
<vxe-column field="cost" :title="$t('base.commodityManagement.cost')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.cost" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="price" :title="$t('base.commodityManagement.price')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.price" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="operate" :title="$t('system.page.operate')" width="100" :resizable="false" show-overflow>
<template #default="{ row }">
<!-- <tooltip-btn
:flat="true"
icon="mdi-pencil-outline"
:tooltip-text="$t('system.page.edit')"
@click="method.editRow(row)"
></tooltip-btn> -->
<tooltip-btn
:flat="true"
icon="mdi-delete-outline"
:tooltip-text="$t('system.page.delete')"
:icon-color="errorColor"
@click="method.deleteRow(row)"
></tooltip-btn>
</template>
</vxe-column>
</vxe-table>
</div>
</v-col>
</v-row>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
<v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import { CommodityVO, CommodityDetailVO } from '@/types/Base/CommodityManagement'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addSpu, updateSpu } from '@/api/base/commodityManagementSetting'
import { getCategoryAll } from '@/api/base/commodityCategorySetting'
import { getSupplierAll } from '@/api/base/supplier'
import { CategoryVO } from '@/types/Base/CommodityCategorySetting'
import { SupplierVO } from '@/types/Base/Supplier'
import { computedSelectTableSearchHeight, SYSTEM_HEIGHT, errorColor } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { removeArrayNull } from '@/utils/common'
import { StringLength } from '@/utils/dataVerification/formRule'
import { isDecimal } from '@/utils/dataVerification/tableRule'
import { exportData } from '@/utils/exportTable'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const xTable = ref()
const props = defineProps<{
showDialog: boolean
form: CommodityVO
}>()
const isShow = computed(() => props.showDialog)
const dialogTitle = computed(() => {
if (props.form.id && props.form.id > 0) {
return 'update'
}
return 'add'
})
const data = reactive({
form: ref<CommodityVO>({
id: 0,
spu_code: '',
spu_name: '',
category_id: 0,
category_name: '',
spu_description: '',
bar_code: '',
supplier_id: 0,
supplier_name: '',
brand: '',
origin: '',
length_unit: 1,
volume_unit: 0,
weight_unit: 1,
detailList: []
}),
tableData: [],
rules: {
spu_code: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.spu_code') }!`,
(val: string) => StringLength(val, 0, 32) === '' || StringLength(val, 0, 32)
],
spu_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.spu_name') }!`,
(val: string) => StringLength(val, 0, 200) === '' || StringLength(val, 0, 200)
],
spu_description: [(val: string) => StringLength(val, 0, 1000) === '' || StringLength(val, 0, 1000)],
bar_code: [(val: string) => StringLength(val, 0, 64) === '' || StringLength(val, 0, 64)],
brand: [(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)],
category_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.category_name') }!`
],
length_unit: [
(val: number) => [0, 1, 2, 3].includes(val) || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.length_unit') }!`
],
volume_unit: [
(val: number) => [0, 1, 2].includes(val) || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.volume_unit') }!`
],
weight_unit: [
(val: number) => [0, 1, 2].includes(val) || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.weight_unit') }!`
],
supplier_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.supplier_name') }!`
]
},
validRules: ref<any>({
sku_code: [
{ required: true, message: `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.sku_code') }` },
{
type: 'string',
min: 0,
max: 32,
message: `${ i18n.global.t('system.checkText.lengthValid') }${ 0 }-${ 32 }`,
trigger: 'change'
}
],
sku_name: [
{ required: true, message: `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.sku_name') }` },
{
type: 'string',
min: 0,
max: 200,
message: `${ i18n.global.t('system.checkText.lengthValid') }${ 0 }-${ 200 }`,
trigger: 'change'
}
],
unit: [
{ required: true, message: `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.unit') }` },
{
type: 'string',
min: 0,
max: 5,
message: `${ i18n.global.t('system.checkText.lengthValid') }${ 0 }-${ 5 }`,
trigger: 'change'
}
],
weight: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
lenght: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
width: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
height: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
volume: [
// {
// validator: isDecimal,
// validNumerical: 'nonNegative',
// length: 8,
// decimalLength: 3,
// trigger: 'change'
// }
],
cost: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 10,
decimalLength: 2,
trigger: 'change'
}
],
price: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 10,
decimalLength: 2,
trigger: 'change'
}
]
}),
combobox: ref<{
length_unit: {
label: string
value: number
}[]
volume_unit: {
label: string
value: number
}[]
weight_unit: {
label: string
value: number
}[]
category_name: {
label: string
value: number
}[]
supplier_name: {
label: string
value: number
}[]
}>({
length_unit: [
{
label: 'mm',
value: 0
},
{
label: 'cm',
value: 1
},
{
label: 'dm',
value: 2
},
{
label: 'm',
value: 3
}
],
volume_unit: [
{
label: 'cm³',
value: 0
},
{
label: 'dm³',
value: 1
},
{
label: 'm³',
value: 2
}
],
weight_unit: [
{
label: 'mg',
value: 0
},
{
label: 'g',
value: 1
},
{
label: 'kg',
value: 2
}
],
category_name: [],
supplier_name: []
})
})
const method = reactive({
// When the commodity type changes, it is mainly used to assign the ID
categoryNameChange: (val: string) => {
if (!val) {
data.form.category_id = 0
} else {
data.form.category_id = data.combobox.category_name.filter((item) => item.label === val)[0].value
}
},
supplierNameChange: (val: string) => {
if (!val) {
data.form.supplier_id = 0
} else {
data.form.supplier_id = data.combobox.supplier_name.filter((item) => item.label === val)[0].value
}
},
// Get the options required by the drop-down box
getCombobox: async () => {
data.combobox.category_name = []
data.combobox.supplier_name = []
const { data: res } = await getCategoryAll()
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.combobox.category_name = res.data
.filter((item: CategoryVO) => item.is_valid)
.map((item: CategoryVO) => ({ value: item.id, label: item.category_name }))
// Get supplier information
const { data: supplierRes } = await getSupplierAll()
if (!supplierRes.isSuccess) {
hookComponent.$message({
type: 'error',
content: supplierRes.errorMessage
})
return
}
data.combobox.supplier_name = supplierRes.data
.filter((item: SupplierVO) => item.is_valid)
.map((item: SupplierVO) => ({ value: item.id, label: item.supplier_name }))
},
closeDialog: () => {
emit('close')
},
insertOneRow: () => {
xTable.value.insertAt(-1)
},
// Export table
exportTable: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.commodityManagement'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
submit: async () => {
const $table = xTable.value
const errMap = await $table.validate(true)
const { valid } = await formRef.value.validate()
if (valid && !errMap) {
if ($table.getTableData().fullData.length === 0) {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.tips.detailLengthIsZero')
})
return
}
const form = { ...data.form }
const insertRecords = $table.getInsertRecords()
form.detailList = []
// Processing detailed data
if (dialogTitle.value === 'add') {
form.detailList = [...insertRecords]
} else {
const updateRecords = $table.getUpdateRecords()
const removeRecords = $table.getRemoveRecords()
form.detailList = [...insertRecords, ...updateRecords]
for (const item of removeRecords) {
item.id = item.id > 0 ? 0 - item.id : item.id
form.detailList.push(item)
}
}
form.detailList = removeArrayNull(form.detailList)
const { data: res } = dialogTitle.value === 'add' ? await addSpu(form) : await updateSpu(form)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
})
emit('saveSuccess')
} else {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.checkText.checkFormFail')
})
}
},
editRow: (row: CommodityDetailVO) => {
const $table = xTable.value
$table.setEditRow(row)
},
deleteRow: (row: CommodityDetailVO) => {
const $table = xTable.value
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteDetailMessage'),
handleConfirm: async () => {
$table.remove(row)
}
})
}
})
const mainFormHeight = computed(() => computedSelectTableSearchHeight({ hasPager: false, hasToolBar: true }))
watch(
() => isShow.value,
(val) => {
if (val) {
method.getCombobox()
data.form = props.form
}
}
)
</script>
<style scoped lang="less">
.mainForm {
background-color: #f9f9f9;
border-radius: 5px;
padding: 20px;
box-sizing: border-box;
overflow: auto;
}
.toolbar {
height: 40px;
}
</style>
<template>
<v-dialog v-model="isShow" width="70%" transition="dialog-top-transition" :persistent="true">
<template #default>
<v-card>
<v-toolbar color="white" :title="`${$t('router.sideBar.commodityManagement')}`"></v-toolbar>
<v-card-text>
<v-row>
<v-col cols="3">
<div class="mainForm" :style="{ height: mainFormHeight }">
<v-form ref="formRef">
<v-text-field
v-model="data.form.spu_code"
:rules="data.rules.spu_code"
:label="$t('base.commodityManagement.spu_code')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-text-field
v-model="data.form.spu_name"
:rules="data.rules.spu_name"
:label="$t('base.commodityManagement.spu_name')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-select
v-model="data.form.category_name"
:items="data.combobox.category_name"
item-title="label"
item-value="label"
:rules="data.rules.category_name"
:label="$t('base.commodityManagement.category_name')"
variant="outlined"
density="compact"
class="mb-4"
clearable
@update:model-value="method.categoryNameChange"
></v-select>
<v-text-field
v-model="data.form.spu_description"
:rules="data.rules.spu_description"
:label="$t('base.commodityManagement.spu_description')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-text-field
v-model="data.form.bar_code"
:rules="data.rules.bar_code"
:label="$t('base.commodityManagement.bar_code')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-select
v-model="data.form.supplier_name"
:items="data.combobox.supplier_name"
:rules="data.rules.supplier_name"
item-title="label"
item-value="label"
:label="$t('base.commodityManagement.supplier_name')"
variant="outlined"
density="compact"
class="mb-4"
clearable
@update:model-value="method.supplierNameChange"
></v-select>
<v-text-field
v-model="data.form.brand"
:rules="data.rules.brand"
:label="$t('base.commodityManagement.brand')"
variant="outlined"
density="compact"
clearable
class="mb-4"
></v-text-field>
<v-select
v-model="data.form.length_unit"
:items="data.combobox.length_unit"
item-title="label"
item-value="value"
:rules="data.rules.length_unit"
:label="$t('base.commodityManagement.length_unit')"
variant="outlined"
density="compact"
class="mb-4"
clearable
></v-select>
<v-select
v-model="data.form.volume_unit"
:items="data.combobox.volume_unit"
item-title="label"
item-value="value"
:rules="data.rules.volume_unit"
:label="$t('base.commodityManagement.volume_unit')"
variant="outlined"
density="compact"
class="mb-4"
clearable
></v-select>
<v-select
v-model="data.form.weight_unit"
:items="data.combobox.weight_unit"
item-title="label"
item-value="value"
:rules="data.rules.weight_unit"
:label="$t('base.commodityManagement.weight_unit')"
variant="outlined"
density="compact"
class="mb-4"
clearable
></v-select>
</v-form>
</div>
</v-col>
<v-col cols="9">
<div class="dataTable">
<div class="toolbar">
<tooltip-btn
icon="mdi-plus"
:tooltip-text="$t('system.page.insertOneRow')"
size="x-small"
@click="method.insertOneRow"
></tooltip-btn>
<tooltip-btn
icon="mdi-export-variant"
:tooltip-text="$t('system.page.export')"
size="x-small"
@click="method.exportTable"
></tooltip-btn>
</div>
<vxe-table
ref="xTable"
keep-source
:column-config="{ minWidth: '100px' }"
:data="data.form.detailList"
:height="SYSTEM_HEIGHT.SELECT_TABLE"
align="center"
:edit-rules="data.validRules"
:edit-config="{ trigger: 'click', mode: 'cell' }"
:mouse-config="{ selected: true }"
:keyboard-config="{ isArrow: true, isDel: true, isEnter: true, isTab: true, isEdit: true, isChecked: true }"
>
<template #empty>
{{ i18n.global.t('system.page.noData') }}
</template>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="sku_code" :title="$t('base.commodityManagement.sku_code')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.sku_code" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="sku_name" :title="$t('base.commodityManagement.sku_name')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.sku_name" type="text"></vxe-input>
</template>
</vxe-column>
<!-- <vxe-column field="supplier_name" :title="$t('base.commodityManagement.supplier_name')"></vxe-column> -->
<!-- <vxe-column field="brand" :title="$t('base.commodityManagement.brand')"></vxe-column> -->
<vxe-column field="unit" :title="$t('base.commodityManagement.unit')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.unit" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="weight" :title="$t('base.commodityManagement.weight')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.weight" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="lenght" :title="$t('base.commodityManagement.lenght')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.lenght" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="width" :title="$t('base.commodityManagement.width')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.width" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="height" :title="$t('base.commodityManagement.height')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.height" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="volume" :title="$t('base.commodityManagement.volume')"> </vxe-column>
<vxe-column field="cost" :title="$t('base.commodityManagement.cost')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.cost" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="price" :title="$t('base.commodityManagement.price')" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.price" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="operate" :title="$t('system.page.operate')" width="100" :resizable="false" show-overflow>
<template #default="{ row }">
<!-- <tooltip-btn
:flat="true"
icon="mdi-pencil-outline"
:tooltip-text="$t('system.page.edit')"
@click="method.editRow(row)"
></tooltip-btn> -->
<tooltip-btn
:flat="true"
icon="mdi-delete-outline"
:tooltip-text="$t('system.page.delete')"
:icon-color="errorColor"
@click="method.deleteRow(row)"
></tooltip-btn>
</template>
</vxe-column>
</vxe-table>
</div>
</v-col>
</v-row>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
<v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import { CommodityVO, CommodityDetailVO } from '@/types/Base/CommodityManagement'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addSpu, updateSpu } from '@/api/base/commodityManagementSetting'
import { getCategoryAll } from '@/api/base/commodityCategorySetting'
import { getSupplierAll } from '@/api/base/supplier'
import { CategoryVO } from '@/types/Base/CommodityCategorySetting'
import { SupplierVO } from '@/types/Base/Supplier'
import { computedSelectTableSearchHeight, SYSTEM_HEIGHT, errorColor } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { removeArrayNull } from '@/utils/common'
import { StringLength } from '@/utils/dataVerification/formRule'
import { isDecimal } from '@/utils/dataVerification/tableRule'
import { exportData } from '@/utils/exportTable'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const xTable = ref()
const props = defineProps<{
showDialog: boolean
form: CommodityVO
}>()
const isShow = computed(() => props.showDialog)
const dialogTitle = computed(() => {
if (props.form.id && props.form.id > 0) {
return 'update'
}
return 'add'
})
const data = reactive({
form: ref<CommodityVO>({
id: 0,
spu_code: '',
spu_name: '',
category_id: 0,
category_name: '',
spu_description: '',
bar_code: '',
supplier_id: 0,
supplier_name: '',
brand: '',
origin: '',
length_unit: 1,
volume_unit: 0,
weight_unit: 1,
detailList: []
}),
tableData: [],
rules: {
spu_code: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.spu_code') }!`,
(val: string) => StringLength(val, 0, 32) === '' || StringLength(val, 0, 32)
],
spu_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.spu_name') }!`,
(val: string) => StringLength(val, 0, 200) === '' || StringLength(val, 0, 200)
],
spu_description: [(val: string) => StringLength(val, 0, 1000) === '' || StringLength(val, 0, 1000)],
bar_code: [(val: string) => StringLength(val, 0, 64) === '' || StringLength(val, 0, 64)],
brand: [(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)],
category_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.category_name') }!`
],
length_unit: [
(val: number) => [0, 1, 2, 3].includes(val) || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.length_unit') }!`
],
volume_unit: [
(val: number) => [0, 1, 2].includes(val) || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.volume_unit') }!`
],
weight_unit: [
(val: number) => [0, 1, 2].includes(val) || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.weight_unit') }!`
],
supplier_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.supplier_name') }!`
]
},
validRules: ref<any>({
sku_code: [
{ required: true, message: `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.sku_code') }` },
{
type: 'string',
min: 0,
max: 32,
message: `${ i18n.global.t('system.checkText.lengthValid') }${ 0 }-${ 32 }`,
trigger: 'change'
}
],
sku_name: [
{ required: true, message: `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.sku_name') }` },
{
type: 'string',
min: 0,
max: 200,
message: `${ i18n.global.t('system.checkText.lengthValid') }${ 0 }-${ 200 }`,
trigger: 'change'
}
],
unit: [
{ required: true, message: `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityManagement.unit') }` },
{
type: 'string',
min: 0,
max: 5,
message: `${ i18n.global.t('system.checkText.lengthValid') }${ 0 }-${ 5 }`,
trigger: 'change'
}
],
weight: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
lenght: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
width: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
height: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 8,
decimalLength: 3,
trigger: 'change'
}
],
volume: [
// {
// validator: isDecimal,
// validNumerical: 'nonNegative',
// length: 8,
// decimalLength: 3,
// trigger: 'change'
// }
],
cost: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 10,
decimalLength: 2,
trigger: 'change'
}
],
price: [
{
validator: isDecimal,
validNumerical: 'nonNegative',
length: 10,
decimalLength: 2,
trigger: 'change'
}
]
}),
combobox: ref<{
length_unit: {
label: string
value: number
}[]
volume_unit: {
label: string
value: number
}[]
weight_unit: {
label: string
value: number
}[]
category_name: {
label: string
value: number
}[]
supplier_name: {
label: string
value: number
}[]
}>({
length_unit: [
{
label: 'mm',
value: 0
},
{
label: 'cm',
value: 1
},
{
label: 'dm',
value: 2
},
{
label: 'm',
value: 3
}
],
volume_unit: [
{
label: 'cm³',
value: 0
},
{
label: 'dm³',
value: 1
},
{
label: 'm³',
value: 2
}
],
weight_unit: [
{
label: 'mg',
value: 0
},
{
label: 'g',
value: 1
},
{
label: 'kg',
value: 2
}
],
category_name: [],
supplier_name: []
})
})
const method = reactive({
// When the commodity type changes, it is mainly used to assign the ID
categoryNameChange: (val: string) => {
if (!val) {
data.form.category_id = 0
} else {
data.form.category_id = data.combobox.category_name.filter((item) => item.label === val)[0].value
}
},
supplierNameChange: (val: string) => {
if (!val) {
data.form.supplier_id = 0
} else {
data.form.supplier_id = data.combobox.supplier_name.filter((item) => item.label === val)[0].value
}
},
// Get the options required by the drop-down box
getCombobox: async () => {
data.combobox.category_name = []
data.combobox.supplier_name = []
const { data: res } = await getCategoryAll()
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.combobox.category_name = res.data
.filter((item: CategoryVO) => item.is_valid)
.map((item: CategoryVO) => ({ value: item.id, label: item.category_name }))
// Get supplier information
const { data: supplierRes } = await getSupplierAll()
if (!supplierRes.isSuccess) {
hookComponent.$message({
type: 'error',
content: supplierRes.errorMessage
})
return
}
data.combobox.supplier_name = supplierRes.data
.filter((item: SupplierVO) => item.is_valid)
.map((item: SupplierVO) => ({ value: item.id, label: item.supplier_name }))
},
closeDialog: () => {
emit('close')
},
insertOneRow: () => {
xTable.value.insertAt(-1)
},
// Export table
exportTable: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.commodityManagement'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
submit: async () => {
const $table = xTable.value
const errMap = await $table.validate(true)
const { valid } = await formRef.value.validate()
if (valid && !errMap) {
if ($table.getTableData().fullData.length === 0) {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.tips.detailLengthIsZero')
})
return
}
const form = { ...data.form }
const insertRecords = $table.getInsertRecords()
form.detailList = []
// Processing detailed data
if (dialogTitle.value === 'add') {
form.detailList = [...insertRecords]
} else {
const updateRecords = $table.getUpdateRecords()
const removeRecords = $table.getRemoveRecords()
form.detailList = [...insertRecords, ...updateRecords]
for (const item of removeRecords) {
item.id = item.id > 0 ? 0 - item.id : item.id
form.detailList.push(item)
}
}
form.detailList = removeArrayNull(form.detailList)
const { data: res } = dialogTitle.value === 'add' ? await addSpu(form) : await updateSpu(form)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
})
emit('saveSuccess')
} else {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.checkText.checkFormFail')
})
}
},
editRow: (row: CommodityDetailVO) => {
const $table = xTable.value
$table.setEditRow(row)
},
deleteRow: (row: CommodityDetailVO) => {
const $table = xTable.value
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteDetailMessage'),
handleConfirm: async () => {
$table.remove(row)
}
})
}
})
const mainFormHeight = computed(() => computedSelectTableSearchHeight({ hasPager: false, hasToolBar: true }))
watch(
() => isShow.value,
(val) => {
if (val) {
method.getCombobox()
data.form = props.form
}
}
)
</script>
<style scoped lang="less">
.mainForm {
background-color: #f9f9f9;
border-radius: 5px;
padding: 20px;
box-sizing: border-box;
overflow: auto;
}
.toolbar {
height: 40px;
}
</style>
1、主页面代码
<!-- supplier Setting -->
<template>
<div class="container">
<div>
<!-- Main Content -->
<v-card class="mt-5">
<v-card-text>
<!-- <v-window v-model="data.activeTab">
<v-window-item> -->
<div class="operateArea">
<v-row no-gutters>
<!-- Operate Btn -->
<v-col cols="12" sm="3" class="col">
<tooltip-btn icon="mdi-plus" :tooltip-text="$t('system.page.add')" @click="method.add()"></tooltip-btn>
<tooltip-btn icon="mdi-refresh" :tooltip-text="$t('system.page.refresh')" @click="method.refresh()"></tooltip-btn>
<tooltip-btn icon="mdi-database-import-outline" :tooltip-text="$t('system.page.import')" @click="method.openDialogImport">
</tooltip-btn>
<tooltip-btn icon="mdi-export-variant" :tooltip-text="$t('system.page.export')" @click="method.exportTable"> </tooltip-btn>
</v-col>
<!-- Search Input -->
<v-col cols="12" sm="9">
<v-row no-gutters @keyup.enter="method.sureSearch">
<v-col cols="12" sm="4"></v-col>
<v-col cols="12" sm="4"></v-col>
<v-col cols="12" sm="4">
<v-text-field
v-model="data.searchForm.supplier_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.supplier.supplier_name')"
variant="solo"
>
</v-text-field>
</v-col>
</v-row>
</v-col>
</v-row>
</div>
<!-- Table -->
<div
class="mt-5"
:style="{
height: cardHeight
}"
>
<vxe-table ref="xTable" :data="data.tableData" :height="tableHeight" align="center">
<template #empty>
{{ i18n.global.t('system.page.noData') }}
</template>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column type="checkbox" width="50"></vxe-column>
<vxe-column field="supplier_name" :title="$t('base.supplier.supplier_name')"></vxe-column>
<vxe-column field="city" :title="$t('base.supplier.city')"></vxe-column>
<vxe-column field="address" :title="$t('base.supplier.address')"></vxe-column>
<vxe-column field="manager" :title="$t('base.supplier.manager')"></vxe-column>
<vxe-column field="email" :title="$t('base.supplier.email')"></vxe-column>
<vxe-column field="contact_tel" :title="$t('base.supplier.contact_tel')"></vxe-column>
<vxe-column field="creator" :title="$t('base.supplier.creator')"></vxe-column>
<vxe-column field="create_time" :title="$t('base.supplier.create_time')">
<template #default="{ row, column }">
<span>{{ formatDate(row[column.property]) }}</span>
</template>
</vxe-column>
<vxe-column field="last_update_time" :title="$t('base.supplier.last_update_time')">
<template #default="{ row, column }">
<span>{{ formatDate(row[column.property]) }}</span>
</template>
</vxe-column>
<vxe-column field="operate" :title="$t('system.page.operate')" width="160" :resizable="false" show-overflow>
<template #default="{ row }">
<tooltip-btn
:flat="true"
icon="mdi-pencil-outline"
:tooltip-text="$t('system.page.edit')"
@click="method.editRow(row)"
></tooltip-btn>
<tooltip-btn
:flat="true"
icon="mdi-delete-outline"
:tooltip-text="$t('system.page.delete')"
:icon-color="errorColor"
@click="method.deleteRow(row)"
></tooltip-btn>
</template>
</vxe-column>
</vxe-table>
<custom-pager
:current-page="data.tablePage.pageIndex"
:page-size="data.tablePage.pageSize"
perfect
:total="data.tablePage.total"
:page-sizes="PAGE_SIZE"
:layouts="PAGE_LAYOUT"
@page-change="method.handlePageChange"
>
</custom-pager>
</div>
<!-- </v-window-item>
</v-window> -->
</v-card-text>
</v-card>
</div>
</div>
<addOrUpdateDialog :show-dialog="data.showDialog" :form="data.dialogForm" @close="method.closeDialog" @saveSuccess="method.saveSuccess" />
<importSupplierTable :show-dialog="data.showDialogImport" @close="method.closeDialogImport" @saveSuccess="method.saveSuccessImport" />
</template>
<script lang="tsx" setup>
import { computed, ref, reactive, onMounted, watch } from 'vue'
import { VxePagerEvents } from 'vxe-table'
import { computedCardHeight, computedTableHeight, errorColor } from '@/constant/style'
import { SupplierVO, DataProps } from '@/types/Base/Supplier'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import tooltipBtn from '@/components/tooltip-btn.vue'
import addOrUpdateDialog from './add-or-update-supplier.vue'
import { hookComponent } from '@/components/system'
import { DEBOUNCE_TIME } from '@/constant/system'
import { setSearchObject } from '@/utils/common'
import { SearchObject } from '@/types/System/Form'
import i18n from '@/languages/i18n'
import { getSupplierList, deleteSupplier } from '@/api/base/supplier'
import importSupplierTable from './import-supplier-table.vue'
import { formatDate } from '@/utils/format/formatSystem'
import customPager from '@/components/custom-pager.vue'
import { exportData } from '@/utils/exportTable'
const xTable = ref()
const data = reactive({
searchForm: {
supplier_name: ''
},
tableData: [],
// activeTab: null,
showDialog: false,
showDialogImport: false,
dialogForm: {
id: 0,
supplier_name: '',
city: '',
address: '',
manager: '',
email: '',
contact_tel: '',
is_valid: true
},
tablePage: {
total: 0,
pageIndex: 1,
pageSize: DEFAULT_PAGE_SIZE,
searchObjects: ref<Array<SearchObject>>([])
},
timer: ref<any>(null)
})
const method = reactive({
// Import Dialog
openDialogImport: () => {
data.showDialogImport = true
},
closeDialogImport: () => {
data.showDialogImport = false
},
saveSuccessImport: () => {
method.refresh()
method.closeDialog()
},
sureSearch: () => {
data.tablePage.searchObjects = setSearchObject(data.searchForm)
method.getData()
},
// Add user
add: () => {
data.dialogForm = {
id: 0,
supplier_name: '',
city: '',
address: '',
manager: '',
email: '',
contact_tel: '',
is_valid: true
}
data.showDialog = true
},
// Shut add or update dialog
closeDialog: () => {
data.showDialog = false
},
// after Add or update success.
saveSuccess: () => {
method.refresh()
method.closeDialog()
},
// Refresh data
refresh: () => {
method.getData()
},
editRow(row: SupplierVO) {
data.dialogForm = JSON.parse(JSON.stringify(row))
data.showDialog = true
},
deleteRow(row: SupplierVO) {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteMessage'),
handleConfirm: async () => {
if (row.id) {
const { data: res } = await deleteSupplier(row.id)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.delete') }${ i18n.global.t('system.tips.success') }`
})
method.refresh()
}
}
})
},
handlePageChange: ref<VxePagerEvents.PageChange>(({ currentPage, pageSize }) => {
data.tablePage.pageIndex = currentPage
data.tablePage.pageSize = pageSize
method.getData()
}),
exportTable: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.supplier'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
getData: async () => {
const { data: res } = await getSupplierList(data.tablePage)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.tableData = res.data.rows
data.tablePage.total = res.data.totals
}
})
onMounted(() => {
method.getData()
})
const cardHeight = computed(() => computedCardHeight({ hasTab: false }))
const tableHeight = computed(() => computedTableHeight({ hasTab: false }))
watch(
() => data.searchForm,
() => {
// debounce
if (data.timer) {
clearTimeout(data.timer)
}
data.timer = setTimeout(() => {
data.timer = null
method.sureSearch()
}, DEBOUNCE_TIME)
},
{
deep: true
}
)
</script>
<style scoped lang="less">
.operateArea {
width: 100%;
min-width: 760px;
display: flex;
align-items: center;
border-radius: 10px;
padding: 0 10px;
}
.col {
display: flex;
align-items: center;
}
</style>
2、窗体代码
<template>
<v-dialog v-model="isShow" :width="'30%'" transition="dialog-top-transition" :persistent="true">
<template #default>
<v-card>
<v-toolbar color="white" :title="`${$t('router.sideBar.supplier')}`"></v-toolbar>
<v-card-text>
<v-form ref="formRef">
<v-text-field
v-model="data.form.supplier_name"
:label="$t('base.supplier.supplier_name')"
:rules="data.rules.supplier_name"
variant="outlined"
></v-text-field>
<v-text-field v-model="data.form.city" :label="$t('base.supplier.city')" :rules="data.rules.city" variant="outlined"></v-text-field>
<v-text-field v-model="data.form.email" :label="$t('base.supplier.email')" :rules="data.rules.email" variant="outlined"></v-text-field>
<v-text-field
v-model="data.form.address"
:label="$t('base.supplier.address')"
:rules="data.rules.address"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.manager"
:label="$t('base.supplier.manager')"
:rules="data.rules.manager"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.contact_tel"
:label="$t('base.supplier.contact_tel')"
:rules="data.rules.contact_tel"
variant="outlined"
></v-text-field>
</v-form>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
<v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import { SupplierVO } from '@/types/Base/Supplier'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addSupplier, updateSupplier } from '@/api/base/supplier'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const props = defineProps<{
showDialog: boolean
form: SupplierVO
}>()
const isShow = computed(() => props.showDialog)
const dialogTitle = computed(() => {
if (props.form.id && props.form.id > 0) {
return 'update'
}
return 'add'
})
const data = reactive({
form: ref<SupplierVO>({
id: 0,
supplier_name: '',
city: '',
address: '',
manager: '',
email: '',
contact_tel: '',
is_valid: true
}),
rules: {
supplier_name: [(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.supplier.supplier_name') }!`],
city: [],
address: [],
manager: [],
email: [],
contact_tel: [],
is_valid: []
}
})
const method = reactive({
closeDialog: () => {
emit('close')
},
submit: async () => {
const { valid } = await formRef.value.validate()
if (valid) {
const { data: res } = dialogTitle.value === 'add' ? await addSupplier(data.form) : await updateSupplier(data.form)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
})
emit('saveSuccess')
} else {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.checkText.checkFormFail')
})
}
}
})
watch(
() => isShow.value,
(val) => {
if (val) {
data.form = props.form
}
}
)
</script>
<style scoped lang="less">
.v-form {
div {
margin-bottom: 7px;
}
}
</style>
<!-- Supplier Setting Import Dialog -->
<template>
<v-dialog v-model="isShow" width="70%" transition="dialog-top-transition" :persistent="true">
<template #default>
<v-card>
<v-toolbar color="white" :title="`${$t('system.page.import')}`"></v-toolbar>
<v-card-text>
<div class="mb-4">
<tooltip-btn icon="mdi-plus" :tooltip-text="$t('system.page.chooseFile')" size="x-small" @click="method.chooseFile"></tooltip-btn>
<tooltip-btn
icon="mdi-export-variant"
:tooltip-text="$t('system.page.exportTemplate')"
size="x-small"
@click="method.exportTemplate"
></tooltip-btn>
<input v-show="false" id="open" ref="uploadExcel" type="file" accept=".xls, .xlsx" @change="method.readExcel" />
</div>
<vxe-table
ref="xTable"
:column-config="{ minWidth: '100px' }"
:data="data.importData"
:height="SYSTEM_HEIGHT.SELECT_TABLE"
:edit-config="{ trigger: 'click', mode: 'cell' }"
:edit-rules="data.validRules"
:export-config="{}"
align="center"
>
<template #empty>
{{ i18n.global.t('system.page.noData') }}
</template>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="operate" width="60" :title="$t('system.page.operate')" :resizable="false">
<template #default="{ row }">
<tooltip-btn
:flat="true"
icon="mdi-delete-outline"
:tooltip-text="$t('system.page.delete')"
:icon-color="errorColor"
@click="method.deleteRow(row)"
></tooltip-btn>
</template>
</vxe-column>
<vxe-column field="supplier_name" :title="$t('base.supplier.supplier_name')"></vxe-column>
<vxe-column field="city" :title="$t('base.supplier.city')"></vxe-column>
<vxe-column field="address" :title="$t('base.supplier.address')"></vxe-column>
<vxe-column field="manager" :title="$t('base.supplier.manager')"></vxe-column>
<vxe-column field="email" :title="$t('base.supplier.email')"></vxe-column>
<vxe-column field="contact_tel" :title="$t('base.supplier.contact_tel')"></vxe-column>
</vxe-table>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
<v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import { VxeTablePropTypes } from 'vxe-table'
import * as XLSX from 'xlsx'
import i18n from '@/languages/i18n'
import { excelImport } from '@/api/base/supplier'
import { hookComponent } from '@/components/system/index'
import { SYSTEM_HEIGHT, errorColor } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { SupplierExcelVO } from '@/types/Base/Supplier'
import { exportData } from '@/utils/exportTable'
const emit = defineEmits(['close', 'saveSuccess'])
const uploadExcel = ref()
const xTable = ref()
const props = defineProps<{
showDialog: boolean
}>()
const isShow = computed(() => props.showDialog)
const data = reactive({
importData: ref<Array<SupplierExcelVO>>([]),
validRules: ref<VxeTablePropTypes.EditRules>({})
})
const method = reactive({
initForm: () => {
data.importData = []
},
closeDialog: () => {
emit('close')
},
submit: async () => {
const isValid = method.valid()
if (!isValid) {
return
}
const $table = xTable.value
// It must be use 'getTableData()' to get all datas with table because it will delete row sometimes.
const importData = $table.getTableData().fullData
const { data: res } = await excelImport(importData)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
})
emit('saveSuccess')
},
valid: () => {
const $table = xTable.value
const importData = $table.getTableData().fullData
if (importData.length <= 0) {
hookComponent.$message({
type: 'error',
content: `${ i18n.global.t('system.tips.detailLengthIsZero') }`
})
return false
}
return true
},
chooseFile: async () => {
uploadExcel.value.value = ''
uploadExcel.value.click()
},
readExcel: async (evnt: any) => {
const files = evnt.target.files
if (files.length <= 0) {
return false
}
const file = files[0]
const fileReader = new FileReader()
fileReader.onload = (ev: ProgressEvent<FileReader>) => {
const fileData = ev?.target?.result
if (fileData) {
const workbook = XLSX.read(fileData, { type: 'binary' })
const wsname = workbook.SheetNames[0]
let ws = XLSX.utils.sheet_to_json(workbook.Sheets[wsname])
let str = JSON.stringify(ws)
str = str.replace(/(/g, '(')
str = str.replace(/)/g, ')')
ws = JSON.parse(str)
data.importData = []
ws.forEach((value: any, index: number, ws: any) => {
data.importData.push({
supplier_name: ws[index][i18n.global.t('base.supplier.supplier_name')] ? ws[index][i18n.global.t('base.supplier.supplier_name')] + '' : '',
city: ws[index][i18n.global.t('base.supplier.city')] ? ws[index][i18n.global.t('base.supplier.city')] + '' : '',
address: ws[index][i18n.global.t('base.supplier.address')] ? ws[index][i18n.global.t('base.supplier.address')] + '' : '',
manager: ws[index][i18n.global.t('base.supplier.manager')] ? ws[index][i18n.global.t('base.supplier.manager')] + '' : '',
email: ws[index][i18n.global.t('base.supplier.email')] ? ws[index][i18n.global.t('base.supplier.email')] + '' : '',
contact_tel: ws[index][i18n.global.t('base.supplier.contact_tel')] ? ws[index][i18n.global.t('base.supplier.contact_tel')] + '' : ''
})
})
}
}
fileReader.readAsBinaryString(file)
},
exportTemplate: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.supplier'),
mode: 'header',
columnFilterMethod({ column }: any) {
return !['checkbox', 'seq'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
deleteRow: (row: SupplierExcelVO) => {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteDetailMessage'),
handleConfirm: async () => {
if (row) {
const $table = xTable.value
$table.remove(row)
}
}
})
}
})
watch(
() => isShow.value,
(val) => {
if (val) {
method.initForm()
}
}
)
</script>
<style scoped lang="less">
.v-form {
div {
margin-bottom: 7px;
}
}
</style>
/// <summary>
/// supplier controller
/// </summary>
[Route("supplier")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class SupplierController : BaseController
{
#region Args
/// <summary>
/// supplier Service
/// </summary>
private readonly ISupplierService _supplierService;
/// <summary>
/// Localizer Service
/// </summary>
private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
#endregion
#region constructor
/// <summary>
/// constructor
/// </summary>
/// <param name="supplierService">supplier Service</param>
/// <param name="stringLocalizer">Localizer</param>
public SupplierController(
ISupplierService supplierService
, IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
)
{
this._supplierService = supplierService;
this._stringLocalizer= stringLocalizer;
}
#endregion
#region Api
/// <summary>
/// page search
/// </summary>
/// <param name="pageSearch">args</param>
/// <returns></returns>
[HttpPost("list")]
public async Task<ResultModel<PageData<SupplierViewModel>>> PageAsync(PageSearch pageSearch)
{
var (data, totals) = await _supplierService.PageAsync(pageSearch, CurrentUser);
return ResultModel<PageData<SupplierViewModel>>.Success(new PageData<SupplierViewModel>
{
Rows = data,
Totals = totals
});
}
/// <summary>
/// get all records
/// </summary>
/// <returns>args</returns>
[HttpGet("all")]
public async Task<ResultModel<List<SupplierViewModel>>> GetAllAsync()
{
var data = await _supplierService.GetAllAsync(CurrentUser);
if (data.Any())
{
return ResultModel<List<SupplierViewModel>>.Success(data);
}
else
{
return ResultModel<List<SupplierViewModel>>.Success(new List<SupplierViewModel>());
}
}
/// <summary>
/// get a record by id
/// </summary>
/// <returns>args</returns>
[HttpGet]
public async Task<ResultModel<SupplierViewModel>> GetAsync(int id)
{
var data = await _supplierService.GetAsync(id);
if (data!=null)
{
return ResultModel<SupplierViewModel>.Success(data);
}
else
{
return ResultModel<SupplierViewModel>.Error(_stringLocalizer["not_exists_entity"]);
}
}
/// <summary>
/// add a new record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPost]
public async Task<ResultModel<int>> AddAsync(SupplierViewModel viewModel)
{
var (id, msg) = await _supplierService.AddAsync(viewModel,CurrentUser);
if (id > 0)
{
return ResultModel<int>.Success(id);
}
else
{
return ResultModel<int>.Error(msg);
}
}
/// <summary>
/// update a record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPut]
public async Task<ResultModel<bool>> UpdateAsync(SupplierViewModel viewModel)
{
var (flag, msg) = await _supplierService.UpdateAsync(viewModel, CurrentUser);
if (flag)
{
return ResultModel<bool>.Success(flag);
}
else
{
return ResultModel<bool>.Error(msg, 400, flag);
}
}
/// <summary>
/// delete a record
/// </summary>
/// <param name="id">id</param>
/// <returns></returns>
[HttpDelete]
public async Task<ResultModel<string>> DeleteAsync(int id)
{
var (flag, msg) = await _supplierService.DeleteAsync(id);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
/// <summary>
/// import suppliers by excel
/// </summary>
/// <param name="excel_datas">excel datas</param>
/// <returns></returns>
[HttpPost("excel")]
public async Task<ResultModel<string>> ExcelAsync(List<SupplierExcelImportViewModel> excel_datas)
{
var (flag, msg) = await _supplierService.ExcelAsync(excel_datas, CurrentUser);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
#endregion
}
1、仓库设置
2、库区设置
2、库位设置
1、主页面代码
<!-- Warehouse Setting -->
<template>
<div class="container">
<div>
<v-tabs v-model="data.activeTab" stacked @update:model-value="method.changeTabs">
<v-tab v-for="(item, index) of tabsConfig" :key="index" :value="item.value">
<v-icon>{{ item.icon }}</v-icon>
<p class="tabItemTitle">{{ item.tabName }}</p>
</v-tab>
</v-tabs>
<!-- Main Content -->
<v-card class="mt-5">
<v-card-text>
<v-window v-model="data.activeTab">
<v-window-item value="tabWarehouse">
<tab-warehouse ref="tabWarehouseRef" />
</v-window-item>
<v-window-item value="tabReservoir">
<tab-reservoir ref="tabReservoirRef" />
</v-window-item>
<v-window-item value="tabLocation">
<tab-location ref="tabLocationRef" />
</v-window-item>
</v-window>
</v-card-text>
</v-card>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, watch, nextTick } from 'vue'
import i18n from '@/languages/i18n'
import tabWarehouse from './tab-warehouse.vue'
import tabReservoir from './tab-reservoir.vue'
import tabLocation from './tab-location.vue'
const tabWarehouseRef = ref()
const tabReservoirRef = ref()
const tabLocationRef = ref()
const tabsConfig = [
{
value: 'tabWarehouse',
icon: 'mdi-warehouse',
tabName: i18n.global.t('base.warehouseSetting.warehouseSetting')
},
{
value: 'tabReservoir',
icon: 'mdi-texture-box',
tabName: i18n.global.t('base.warehouseSetting.reservoirSetting')
},
{
value: 'tabLocation',
icon: 'mdi-library-shelves ',
tabName: i18n.global.t('base.warehouseSetting.locationSetting')
}
]
const data = reactive({
activeTab: '',
isLoadWarehouseData: false,
isLoadReservoirData: false,
isLoadLocationData: false
})
const method = reactive({
changeTabs: (e: any): void => {
nextTick(() => {
switch (e) {
case 'tabWarehouse':
// Tips:Must be write the nextTick so that can get DOM!!
if (tabWarehouseRef?.value?.getWarehouseList) {
tabWarehouseRef.value.getWarehouseList()
}
break
case 'tabReservoir':
if (tabReservoirRef?.value?.getWarehouseAreaList) {
tabReservoirRef.value.getWarehouseAreaList()
}
break
case 'tabLocation':
if (tabLocationRef?.value?.getGoodsLocationList) {
tabLocationRef.value.getGoodsLocationList()
}
break
}
})
}
})
onMounted(() => {})
</script>
<style scoped lang="less">
.operateArea {
width: 100%;
min-width: 760px;
display: flex;
align-items: center;
border-radius: 10px;
padding: 0 10px;
}
.col {
display: flex;
align-items: center;
}
</style>
2、窗体代码
<!-- Warehouse Setting Operate Dialog -->
<template>
<v-dialog v-model="isShow" :width="'30%'" transition="dialog-top-transition" :persistent="true">
<template #default>
<v-card>
<v-toolbar color="white" :title="`${$t('router.sideBar.warehouseSetting')}`"></v-toolbar>
<v-card-text>
<v-form ref="formRef">
<v-text-field
v-model="data.form.warehouse_name"
:label="$t('base.warehouseSetting.warehouse_name')"
:rules="data.rules.warehouse_name"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.city"
:label="$t('base.warehouseSetting.city')"
:rules="data.rules.city"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.address"
:label="$t('base.warehouseSetting.address')"
:rules="data.rules.address"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.contact_tel"
:label="$t('base.warehouseSetting.contact_tel')"
:rules="data.rules.contact_tel"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.email"
:label="$t('base.warehouseSetting.email')"
:rules="data.rules.email"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.manager"
:label="$t('base.warehouseSetting.manager')"
:rules="data.rules.manager"
variant="outlined"
clearable
></v-text-field>
<v-switch
v-model="data.form.is_valid"
color="primary"
:label="$t('base.warehouseSetting.is_valid')"
:rules="data.rules.is_valid"
></v-switch>
</v-form>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
<v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addWarehouse, updateWarehouse } from '@/api/base/warehouseSetting'
import { WarehouseVO } from '@/types/Base/Warehouse'
import { StringLength } from '@/utils/dataVerification/formRule'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const props = defineProps<{
showDialog: boolean
form: WarehouseVO
}>()
const isShow = computed(() => props.showDialog)
const dialogTitle = computed(() => {
if (props.form.id && props.form.id > 0) {
return 'update'
}
return 'add'
})
const data = reactive({
form: ref<WarehouseVO>({
id: 0,
warehouse_name: '',
city: '',
address: '',
contact_tel: '',
email: '',
manager: '',
is_valid: true
}),
rules: {
warehouse_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.warehouse_name') }!`,
(val: string) => StringLength(val, 0, 32) === '' || StringLength(val, 0, 32)
],
city: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.city') }!`,
(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)
],
address: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.address') }!`,
(val: string) => StringLength(val, 0, 256) === '' || StringLength(val, 0, 256)
],
contact_tel: [(val: string) => StringLength(val, 0, 64) === '' || StringLength(val, 0, 64)],
email: [(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)],
manager: [(val: string) => StringLength(val, 0, 64) === '' || StringLength(val, 0, 64)],
is_valid: []
}
})
const method = reactive({
closeDialog: () => {
emit('close')
},
initForm: () => {
data.form = props.form
},
submit: async () => {
const { valid } = await formRef.value.validate()
if (valid) {
const { data: res } = dialogTitle.value === 'add' ? await addWarehouse(data.form) : await updateWarehouse(data.form)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
})
emit('saveSuccess')
} else {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.checkText.checkFormFail')
})
}
}
})
watch(
() => isShow.value,
(val) => {
if (val) {
method.initForm()
}
}
)
</script>
<style scoped lang="less">
.v-form {
div {
margin-bottom: 7px;
}
}
</style>
<!-- Reservoir Setting Operate Dialog -->
<template>
<v-dialog v-model="isShow" :width="'30%'" transition="dialog-top-transition" :persistent="true">
<template #default>
<v-card>
<v-toolbar color="white" :title="`${$t('base.warehouseSetting.reservoirSetting')}`"></v-toolbar>
<v-card-text>
<v-form ref="formRef">
<v-select
v-model="data.form.warehouse_id"
:items="data.combobox.warehouse_name"
item-title="label"
item-value="value"
:rules="data.rules.warehouse_name"
:label="$t('base.warehouseSetting.warehouse_name')"
variant="outlined"
clearable
@update:model-value="method.changeWarehouse"
></v-select>
<v-text-field
v-model="data.form.area_name"
:label="$t('base.warehouseSetting.area_name')"
:rules="data.rules.area_name"
variant="outlined"
clearable
></v-text-field>
<v-select
v-model="data.form.area_property"
:items="data.combobox.area_property"
item-title="label"
item-value="value"
:rules="data.rules.area_property"
:label="$t('base.warehouseSetting.area_property')"
variant="outlined"
clearable
></v-select>
<v-switch
v-model="data.form.is_valid"
color="primary"
:label="$t('base.warehouseSetting.is_valid')"
:rules="data.rules.is_valid"
></v-switch>
</v-form>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
<v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addWarehouseArea, updateWarehouseArea, getWarehouseSelect } from '@/api/base/warehouseSetting'
import { WarehouseAreaVO, AreaProperty } from '@/types/Base/Warehouse'
import { StringLength } from '@/utils/dataVerification/formRule'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const props = defineProps<{
showDialog: boolean
form: WarehouseAreaVO
}>()
const isShow = computed(() => props.showDialog)
const dialogTitle = computed(() => {
if (props.form.id && props.form.id > 0) {
return 'update'
}
return 'add'
})
const data = reactive({
form: ref<WarehouseAreaVO>({
id: 0,
warehouse_id: 0,
parent_id: 0,
warehouse_name: '',
area_name: '',
area_property: AreaProperty.picking_area,
is_valid: true
}),
rules: {
warehouse_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.warehouse_name') }!`
],
area_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.area_name') }!`,
(val: string) => StringLength(val, 0, 32) === '' || StringLength(val, 0, 32)
],
area_property: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.area_property') }!`
],
is_valid: []
},
combobox: ref<{
warehouse_name: {
label: string
value: number
}[]
area_property: {
label: string
value: AreaProperty
}[]
}>({
warehouse_name: [],
area_property: [
{
label: i18n.global.t('base.warehouseSetting.picking_area'),
value: AreaProperty.picking_area
},
{
label: i18n.global.t('base.warehouseSetting.stocking_area'),
value: AreaProperty.stocking_area
},
{
label: i18n.global.t('base.warehouseSetting.receiving_area'),
value: AreaProperty.receiving_area
},
{
label: i18n.global.t('base.warehouseSetting.return_area'),
value: AreaProperty.return_area
},
{
label: i18n.global.t('base.warehouseSetting.defective_area'),
value: AreaProperty.defective_area
},
{
label: i18n.global.t('base.warehouseSetting.inventory_area'),
value: AreaProperty.inventory_area
}
]
})
})
const method = reactive({
getCombobox: async () => {
data.combobox.warehouse_name = []
const { data: res } = await getWarehouseSelect()
if (!res.isSuccess) {
return
}
for (const item of res.data) {
data.combobox.warehouse_name.push({
label: item.name,
// WarehouseID is a numberic type
value: Number(item.value)
})
}
},
closeDialog: () => {
emit('close')
},
initForm: () => {
data.form = props.form
},
changeWarehouse: (warehouseID: any) => {
// Find the ID corresponding value
const warehouse = data.combobox.warehouse_name.find((item) => item.value === warehouseID)
if (warehouse) {
data.form.warehouse_name = warehouse.label
data.form.warehouse_id = warehouseID
}
},
submit: async () => {
const { valid } = await formRef.value.validate()
if (valid) {
const { data: res } = dialogTitle.value === 'add' ? await addWarehouseArea(data.form) : await updateWarehouseArea(data.form)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
})
emit('saveSuccess')
} else {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.checkText.checkFormFail')
})
}
}
})
watch(
() => isShow.value,
(val) => {
if (val) {
method.initForm()
method.getCombobox()
}
}
)
</script>
<style scoped lang="less">
.v-form {
div {
margin-bottom: 7px;
}
}
</style>
<!-- Location Setting Operate Dialog -->
<template>
<v-dialog v-model="isShow" :width="'30%'" transition="dialog-top-transition" :persistent="true">
<template #default>
<v-card>
<v-toolbar color="white" :title="`${$t('base.warehouseSetting.locationSetting')}`"></v-toolbar>
<v-card-text>
<v-form ref="formRef">
<v-select
v-model="data.form.warehouse_id"
:items="data.combobox.warehouse_name"
item-title="label"
item-value="value"
:rules="data.rules.warehouse_name"
:label="$t('base.warehouseSetting.warehouse_name')"
variant="outlined"
clearable
@update:model-value="method.changeWarehouse"
></v-select>
<v-select
v-model="data.form.warehouse_area_id"
:items="data.combobox.warehouse_area_name"
item-title="label"
item-value="value"
:rules="data.rules.warehouse_area_name"
:label="$t('base.warehouseSetting.area_name')"
variant="outlined"
clearable
@update:model-value="method.changeWarehouseArea"
></v-select>
<v-select
v-model="data.form.warehouse_area_property"
:items="data.combobox.area_property"
item-title="label"
item-value="value"
:rules="data.rules.warehouse_area_property"
:label="$t('base.warehouseSetting.area_property')"
variant="outlined"
disabled
clearable
></v-select>
<v-text-field
v-model="data.form.location_name"
:label="$t('base.warehouseSetting.location_name')"
:rules="data.rules.location_name"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.location_length"
:label="$t('base.warehouseSetting.location_length')"
:rules="data.rules.location_length"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.location_width"
:label="$t('base.warehouseSetting.location_width')"
:rules="data.rules.location_width"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.location_heigth"
:label="$t('base.warehouseSetting.location_heigth')"
:rules="data.rules.location_heigth"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.location_volume"
:label="$t('base.warehouseSetting.location_volume')"
:rules="data.rules.location_volume"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.location_load"
:label="$t('base.warehouseSetting.location_load')"
:rules="data.rules.location_load"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.roadway_number"
:label="$t('base.warehouseSetting.roadway_number')"
:rules="data.rules.roadway_number"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.shelf_number"
:label="$t('base.warehouseSetting.shelf_number')"
:rules="data.rules.shelf_number"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.layer_number"
:label="$t('base.warehouseSetting.layer_number')"
:rules="data.rules.layer_number"
variant="outlined"
clearable
></v-text-field>
<v-text-field
v-model="data.form.tag_number"
:label="$t('base.warehouseSetting.tag_number')"
:rules="data.rules.tag_number"
variant="outlined"
clearable
></v-text-field>
<v-switch
v-model="data.form.is_valid"
color="primary"
:label="$t('base.warehouseSetting.is_valid')"
:rules="data.rules.is_valid"
></v-switch>
</v-form>
</v-card-text>
<v-card-actions class="justify-end">
<v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
<v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
</v-card-actions>
</v-card>
</template>
</v-dialog>
</template>
<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import { hookComponent } from '@/components/system/index'
import { addGoodsLocation, updateGoodsLocation, getWarehouseSelect, getWarehouseAreaSelect } from '@/api/base/warehouseSetting'
import { GoodsLocationVO, AreaProperty } from '@/types/Base/Warehouse'
import i18n from '@/languages/i18n'
import { StringLength, IsDecimal } from '@/utils/dataVerification/formRule'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const props = defineProps<{
showDialog: boolean
form: GoodsLocationVO
}>()
const isShow = computed(() => props.showDialog)
const dialogTitle = computed(() => {
if (props.form.id && props.form.id > 0) {
return 'update'
}
return 'add'
})
const data = reactive({
form: ref<GoodsLocationVO>({
id: 0,
warehouse_name: '',
warehouse_area_name: '',
location_name: '',
location_length: 0,
location_width: 0,
location_heigth: 0,
location_volume: 0,
location_load: 0,
roadway_number: '',
shelf_number: '',
layer_number: '',
tag_number: '',
is_valid: true
}),
rules: {
warehouse_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.warehouse_name') }!`,
(val: string) => StringLength(val, 0, 32) === '' || StringLength(val, 0, 32)
],
warehouse_area_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.area_name') }!`,
(val: string) => StringLength(val, 0, 32) === '' || StringLength(val, 0, 32)
],
warehouse_area_property: [],
location_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.warehouseSetting.location_name') }!`,
(val: string) => StringLength(val, 0, 64) === '' || StringLength(val, 0, 64)
],
location_length: [(val: number) => IsDecimal(val, 'nonNegative', 5, 2) === '' || IsDecimal(val, 'nonNegative', 5, 2)],
location_width: [(val: number) => IsDecimal(val, 'nonNegative', 5, 2) === '' || IsDecimal(val, 'nonNegative', 5, 2)],
location_heigth: [(val: number) => IsDecimal(val, 'nonNegative', 5, 2) === '' || IsDecimal(val, 'nonNegative', 5, 2)],
location_volume: [(val: number) => IsDecimal(val, 'nonNegative', 12, 2) === '' || IsDecimal(val, 'nonNegative', 12, 2)],
location_load: [(val: number) => IsDecimal(val, 'nonNegative', 8, 2) === '' || IsDecimal(val, 'nonNegative', 8, 2)],
roadway_number: [(val: string) => StringLength(val, 0, 10) === '' || StringLength(val, 0, 10)],
shelf_number: [(val: string) => StringLength(val, 0, 10) === '' || StringLength(val, 0, 10)],
layer_number: [(val: string) => StringLength(val, 0, 10) === '' || StringLength(val, 0, 10)],
tag_number: [(val: string) => StringLength(val, 0, 10) === '' || StringLength(val, 0, 10)],
is_valid: []
},
combobox: ref<{
warehouse_name: {
label: string
value: number
}[]
warehouse_area_name: {
label: string
value: number
meta: any
}[]
area_property: {
label: string
value: AreaProperty
}[]
}>({
warehouse_name: [],
warehouse_area_name: [],
area_property: [
{
label: i18n.global.t('base.warehouseSetting.picking_area'),
value: AreaProperty.picking_area
},
{
label: i18n.global.t('base.warehouseSetting.stocking_area'),
value: AreaProperty.stocking_area
},
{
label: i18n.global.t('base.warehouseSetting.receiving_area'),
value: AreaProperty.receiving_area
},
{
label: i18n.global.t('base.warehouseSetting.return_area'),
value: AreaProperty.return_area
},
{
label: i18n.global.t('base.warehouseSetting.defective_area'),
value: AreaProperty.defective_area
},
{
label: i18n.global.t('base.warehouseSetting.inventory_area'),
value: AreaProperty.inventory_area
}
]
})
})
const method = reactive({
changeWarehouse: (warehouseID: any) => {
data.combobox.warehouse_area_name = []
if (!warehouseID) {
method.initWarehouseArea()
return
}
// Find the ID corresponding value
const warehouse = data.combobox.warehouse_name.find((item) => item.value === warehouseID)
if (warehouse) {
data.form.warehouse_name = warehouse.label
data.form.warehouse_id = warehouseID
// Clear messages of warehouse area when warehouse changed.
method.initWarehouseArea()
method.getWarehouseAreaSelect(warehouseID)
}
},
changeWarehouseArea: (warehouseAreaID: any) => {
if (!warehouseAreaID) {
method.initWarehouseArea()
return
}
// Find the ID corresponding value
const warehouse = data.combobox.warehouse_area_name.find((item) => item.value === warehouseAreaID)
if (warehouse) {
data.form.warehouse_area_name = warehouse.label
data.form.warehouse_area_id = warehouseAreaID
data.form.warehouse_area_property = warehouse.meta
}
},
// Clear messages of warehouse area when warehouse changed.
initWarehouseArea() {
delete data.form.warehouse_area_id
data.form.warehouse_area_name = ''
delete data.form.warehouse_area_property
},
getWarehouseSelect: async () => {
data.combobox.warehouse_name = []
const { data: res } = await getWarehouseSelect()
if (!res.isSuccess) {
return
}
for (const item of res.data) {
data.combobox.warehouse_name.push({
label: item.name,
// WarehouseID is a numeric type
value: Number(item.value)
})
}
},
// Get warehouse area select when warehouse changed.
getWarehouseAreaSelect: async (warehouseID: number) => {
data.combobox.warehouse_area_name = []
const { data: res } = await getWarehouseAreaSelect(warehouseID)
if (!res.isSuccess) {
return
}
for (const item of res.data) {
data.combobox.warehouse_area_name.push({
label: item.area_name,
// ID: WarehouseAreaID
value: item.id,
// Custom Property
meta: item.area_property
})
}
},
closeDialog: () => {
emit('close')
},
initForm: () => {
data.form = props.form
},
submit: async () => {
const { valid } = await formRef.value.validate()
if (valid) {
const { data: res } = dialogTitle.value === 'add' ? await addGoodsLocation(data.form) : await updateGoodsLocation(data.form)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
})
emit('saveSuccess')
} else {
hookComponent.$message({
type: 'error',
content: i18n.global.t('system.checkText.checkFormFail')
})
}
}
})
watch(
() => isShow.value,
(val) => {
if (val) {
method.initForm()
method.getWarehouseSelect()
}
}
)
</script>
<style scoped lang="less">
.v-form {
div {
margin-bottom: 7px;
}
}
</style>
/// <summary>
/// warehouse controller
/// </summary>
[Route("warehouse")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class WarehouseController : BaseController
{
#region Args
/// <summary>
/// warehouse Service
/// </summary>
private readonly IWarehouseService _warehouseService;
/// <summary>
/// Localizer Service
/// </summary>
private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
#endregion
#region constructor
/// <summary>
/// constructor
/// </summary>
/// <param name="warehouseService">warehouse Service</param>
/// <param name="stringLocalizer">Localizer</param>
public WarehouseController(
IWarehouseService warehouseService
, IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
)
{
this._warehouseService = warehouseService;
this._stringLocalizer= stringLocalizer;
}
#endregion
#region Api
/// <summary>
/// get select items
/// </summary>
/// <returns></returns>
[HttpGet("select-item")]
public async Task<ResultModel<List<FormSelectItem>>> GetSelectItemsAsnyc()
{
var datas = await _warehouseService.GetSelectItemsAsnyc(CurrentUser);
return ResultModel<List<FormSelectItem>>.Success(datas);
}
/// <summary>
/// page search
/// </summary>
/// <param name="pageSearch">args</param>
/// <returns></returns>
[HttpPost("list")]
public async Task<ResultModel<PageData<WarehouseViewModel>>> PageAsync(PageSearch pageSearch)
{
var (data, totals) = await _warehouseService.PageAsync(pageSearch, CurrentUser);
return ResultModel<PageData<WarehouseViewModel>>.Success(new PageData<WarehouseViewModel>
{
Rows = data,
Totals = totals
});
}
/// <summary>
/// get all records
/// </summary>
/// <returns>args</returns>
[HttpGet("all")]
public async Task<ResultModel<List<WarehouseViewModel>>> GetAllAsync()
{
var data = await _warehouseService.GetAllAsync(CurrentUser);
if (data.Any())
{
return ResultModel<List<WarehouseViewModel>>.Success(data);
}
else
{
return ResultModel<List<WarehouseViewModel>>.Success(new List<WarehouseViewModel>());
}
}
/// <summary>
/// get a record by id
/// </summary>
/// <returns>args</returns>
[HttpGet]
public async Task<ResultModel<WarehouseViewModel>> GetAsync(int id)
{
var data = await _warehouseService.GetAsync(id);
if (data!=null)
{
return ResultModel<WarehouseViewModel>.Success(data);
}
else
{
return ResultModel<WarehouseViewModel>.Error(_stringLocalizer["not_exists_entity"]);
}
}
/// <summary>
/// add a new record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPost]
public async Task<ResultModel<int>> AddAsync(WarehouseViewModel viewModel)
{
var (id, msg) = await _warehouseService.AddAsync(viewModel,CurrentUser);
if (id > 0)
{
return ResultModel<int>.Success(id);
}
else
{
return ResultModel<int>.Error(msg);
}
}
/// <summary>
/// update a record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPut]
public async Task<ResultModel<bool>> UpdateAsync(WarehouseViewModel viewModel)
{
var (flag, msg) = await _warehouseService.UpdateAsync(viewModel,CurrentUser);
if (flag)
{
return ResultModel<bool>.Success(flag);
}
else
{
return ResultModel<bool>.Error(msg, 400, flag);
}
}
/// <summary>
/// delete a record
/// </summary>
/// <param name="id">id</param>
/// <returns></returns>
[HttpDelete]
public async Task<ResultModel<string>> DeleteAsync(int id)
{
var (flag, msg) = await _warehouseService.DeleteAsync(id);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
/// <summary>
/// import warehouses by excel
/// </summary>
/// <param name="excel_datas">excel datas</param>
/// <returns></returns>
[HttpPost("excel")]
public async Task<ResultModel<string>> ExcelAsync(List<WarehouseExcelImportViewModel> excel_datas)
{
var (flag, msg) = await _warehouseService.ExcelAsync(excel_datas, CurrentUser);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
#endregion
}
/// <summary>
/// warehousearea controller
/// </summary>
[Route("warehousearea")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class WarehouseareaController : BaseController
{
#region Args
/// <summary>
/// warehousearea Service
/// </summary>
private readonly IWarehouseareaService _warehouseareaService;
/// <summary>
/// Localizer Service
/// </summary>
private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
#endregion
#region constructor
/// <summary>
/// constructor
/// </summary>
/// <param name="warehouseareaService">warehousearea Service</param>
/// <param name="stringLocalizer">Localizer</param>
public WarehouseareaController(
IWarehouseareaService warehouseareaService
, IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
)
{
this._warehouseareaService = warehouseareaService;
this._stringLocalizer= stringLocalizer;
}
#endregion
#region Api
/// <summary>
/// get warehousearea select items by warehouse_id
/// </summary>
/// <returns></returns>
[HttpGet("areas-by-warehouse_id")]
public async Task<ResultModel<List<FormSelectItem>>> GetSelectItemsAsnyc(int warehouse_id)
{
var datas = await _warehouseareaService.GetWarehouseareaByWarehouse_id(warehouse_id,CurrentUser);
return ResultModel<List<FormSelectItem>>.Success(datas);
}
/// <summary>
/// page search
/// </summary>
/// <param name="pageSearch">args</param>
/// <returns></returns>
[HttpPost("list")]
public async Task<ResultModel<PageData<WarehouseareaViewModel>>> PageAsync(PageSearch pageSearch)
{
var (data, totals) = await _warehouseareaService.PageAsync(pageSearch, CurrentUser);
return ResultModel<PageData<WarehouseareaViewModel>>.Success(new PageData<WarehouseareaViewModel>
{
Rows = data,
Totals = totals
});
}
/// <summary>
/// get all records
/// </summary>
/// <returns>args</returns>
[HttpGet("all")]
public async Task<ResultModel<List<WarehouseareaViewModel>>> GetAllAsync(int warehouse_id)
{
var data = await _warehouseareaService.GetAllAsync( warehouse_id, CurrentUser);
if (data.Any())
{
return ResultModel<List<WarehouseareaViewModel>>.Success(data);
}
else
{
return ResultModel<List<WarehouseareaViewModel>>.Success(new List<WarehouseareaViewModel>());
}
}
/// <summary>
/// get a record by id
/// </summary>
/// <returns>args</returns>
[HttpGet]
public async Task<ResultModel<WarehouseareaViewModel>> GetAsync(int id)
{
var data = await _warehouseareaService.GetAsync(id);
if (data!=null)
{
return ResultModel<WarehouseareaViewModel>.Success(data);
}
else
{
return ResultModel<WarehouseareaViewModel>.Error(_stringLocalizer["not_exists_entity"]);
}
}
/// <summary>
/// add a new record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPost]
public async Task<ResultModel<int>> AddAsync(WarehouseareaViewModel viewModel)
{
var (id, msg) = await _warehouseareaService.AddAsync(viewModel,CurrentUser);
if (id > 0)
{
return ResultModel<int>.Success(id);
}
else
{
return ResultModel<int>.Error(msg);
}
}
/// <summary>
/// update a record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPut]
public async Task<ResultModel<bool>> UpdateAsync(WarehouseareaViewModel viewModel)
{
var (flag, msg) = await _warehouseareaService.UpdateAsync(viewModel,CurrentUser);
if (flag)
{
return ResultModel<bool>.Success(flag);
}
else
{
return ResultModel<bool>.Error(msg, 400, flag);
}
}
/// <summary>
/// delete a record
/// </summary>
/// <param name="id">id</param>
/// <returns></returns>
[HttpDelete]
public async Task<ResultModel<string>> DeleteAsync(int id)
{
var (flag, msg) = await _warehouseareaService.DeleteAsync(id);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
#endregion
}
/// <summary>
/// goodslocation controller
/// </summary>
[Route("goodslocation")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class GoodslocationController : BaseController
{
#region Args
/// <summary>
/// goodslocation Service
/// </summary>
private readonly IGoodslocationService _goodslocationService;
/// <summary>
/// Localizer Service
/// </summary>
private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
#endregion
#region constructor
/// <summary>
/// constructor
/// </summary>
/// <param name="goodslocationService">goodslocation Service</param>
/// <param name="stringLocalizer">Localizer</param>
public GoodslocationController(
IGoodslocationService goodslocationService
, IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
)
{
this._goodslocationService = goodslocationService;
this._stringLocalizer= stringLocalizer;
}
#endregion
#region Api
/// <summary>
/// get select items
/// </summary>
/// <returns></returns>
[HttpGet("location-by-warehouseare_id")]
public async Task<ResultModel<List<FormSelectItem>>> GetSelectItemsAsnyc(int warehousearea_id)
{
var datas = await _goodslocationService.GetGoodslocationByWarehouse_area_id(warehousearea_id, CurrentUser);
return ResultModel<List<FormSelectItem>>.Success(datas);
}
/// <summary>
/// page search
/// </summary>
/// <param name="pageSearch">args</param>
/// <returns></returns>
[HttpPost("list")]
public async Task<ResultModel<PageData<GoodslocationViewModel>>> PageAsync(PageSearch pageSearch)
{
var (data, totals) = await _goodslocationService.PageAsync(pageSearch, CurrentUser);
return ResultModel<PageData<GoodslocationViewModel>>.Success(new PageData<GoodslocationViewModel>
{
Rows = data,
Totals = totals
});
}
/// <summary>
/// get all records
/// </summary>
/// <returns>args</returns>
[HttpGet("all")]
public async Task<ResultModel<List<GoodslocationViewModel>>> GetAllAsync()
{
var data = await _goodslocationService.GetAllAsync(CurrentUser);
if (data.Any())
{
return ResultModel<List<GoodslocationViewModel>>.Success(data);
}
else
{
return ResultModel<List<GoodslocationViewModel>>.Success(new List<GoodslocationViewModel>());
}
}
/// <summary>
/// get a record by id
/// </summary>
/// <returns>args</returns>
[HttpGet]
public async Task<ResultModel<GoodslocationViewModel>> GetAsync(int id)
{
var data = await _goodslocationService.GetAsync(id);
if (data!=null)
{
return ResultModel<GoodslocationViewModel>.Success(data);
}
else
{
return ResultModel<GoodslocationViewModel>.Error(_stringLocalizer["not_exists_entity"]);
}
}
/// <summary>
/// add a new record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPost]
public async Task<ResultModel<int>> AddAsync(GoodslocationViewModel viewModel)
{
var (id, msg) = await _goodslocationService.AddAsync(viewModel,CurrentUser);
if (id > 0)
{
return ResultModel<int>.Success(id);
}
else
{
return ResultModel<int>.Error(msg);
}
}
/// <summary>
/// update a record
/// </summary>
/// <param name="viewModel">args</param>
/// <returns></returns>
[HttpPut]
public async Task<ResultModel<bool>> UpdateAsync(GoodslocationViewModel viewModel)
{
var (flag, msg) = await _goodslocationService.UpdateAsync(viewModel, CurrentUser);
if (flag)
{
return ResultModel<bool>.Success(flag);
}
else
{
return ResultModel<bool>.Error(msg, 400, flag);
}
}
/// <summary>
/// delete a record
/// </summary>
/// <param name="id">id</param>
/// <returns></returns>
[HttpDelete]
public async Task<ResultModel<string>> DeleteAsync(int id)
{
var (flag, msg) = await _goodslocationService.DeleteAsync(id);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
#endregion
}