基础设置主要分为以下几个模块:
这边需要提下客户和货主的概念:客户是与仓储签订直接合同的甲方,货主是拥有货权的人。
实际情况下,货主会委托某人或某企业管理自己的货物,而这个管理人或企业会与仓储签订合同,使用仓储的软硬件资源。
货主是客户的甲方,客户是仓储的甲方(货主和客户也可能是同一人或企业)。
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-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="4"> </v-col>
<v-col cols="4"> </v-col>
<v-col cols="4">
<v-text-field
v-model="data.searchForm.goods_owner_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.ownerOfCargo.goods_owner_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 field="goods_owner_name" :title="$t('base.ownerOfCargo.goods_owner_name')"></vxe-column>
<vxe-column field="city" :title="$t('base.ownerOfCargo.city')"></vxe-column>
<vxe-column field="address" :title="$t('base.ownerOfCargo.address')"></vxe-column>
<vxe-column field="contact_tel" :title="$t('base.ownerOfCargo.contact_tel')"></vxe-column>
<vxe-column field="manager" :title="$t('base.ownerOfCargo.manager')"></vxe-column>
<vxe-column field="creator" :title="$t('base.ownerOfCargo.creator')"></vxe-column>
<vxe-column field="create_time" :title="$t('base.ownerOfCargo.create_time')"></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-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" />
<import-table :show-dialog="data.showDialogImport" @close="method.closeDialogImport" @saveSuccess="method.saveSuccessImport" />
</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 { OwnerOfCargoVO, DataProps } from '@/types/Base/OwnerOfCargo'
import { getOwnerOfCargoByPage, deleteOwnerOfCargo } from '@/api/base/ownerOfCargo'
import { hookComponent } from '@/components/system'
import addOrUpdateDialog from './add-or-update-owner-of-cargo.vue'
import i18n from '@/languages/i18n'
import importTable from './import-table.vue'
import { setSearchObject } from '@/utils/common'
import customPager from '@/components/custom-pager.vue'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import { exportData } from '@/utils/exportTable'
import { DEBOUNCE_TIME } from '@/constant/system'
const xTable = ref()
const data: DataProps = reactive({
searchForm: {
goods_owner_name: ''
},
showDialogImport: false,
tableData: [],
// Dialog info
showDialog: false,
dialogForm: {
id: 0,
goods_owner_name: '',
city: '',
address: '',
contact_tel: '',
manager: ''
},
tablePage: {
total: 0,
pageIndex: 1,
pageSize: DEFAULT_PAGE_SIZE
},
timer: null
})
const method = reactive({
// When change paging
handlePageChange: ref<VxePagerEvents.PageChange>(({ currentPage, pageSize }) => {
data.tablePage.pageIndex = currentPage
data.tablePage.pageSize = pageSize
method.refresh()
}),
// Import Dialog
openDialogImport: () => {
data.showDialogImport = true
},
closeDialogImport: () => {
data.showDialogImport = false
},
saveSuccessImport: () => {
method.refresh()
method.closeDialogImport()
},
sureSearch: () => {
data.tablePage.searchObjects = setSearchObject(data.searchForm)
method.getOwnerOfCargoList()
},
// Find Data by Pagination
getOwnerOfCargoList: async () => {
const { data: res } = await getOwnerOfCargoByPage(data.tablePage)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.tableData = res.data.rows
data.tablePage.total = res.data.totals
},
// Add user
add: () => {
data.dialogForm = {
id: 0,
goods_owner_name: '',
city: '',
address: '',
contact_tel: '',
manager: ''
}
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.getOwnerOfCargoList()
},
editRow(row: OwnerOfCargoVO) {
data.dialogForm = JSON.parse(JSON.stringify(row))
data.showDialog = true
},
deleteRow(row: OwnerOfCargoVO) {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteMessage'),
handleConfirm: async () => {
if (row.id) {
const { data: res } = await deleteOwnerOfCargo(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.ownerOfCargo'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
}
})
onMounted(async () => {
await method.getOwnerOfCargoList()
})
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.ownerOfCargo')}`"></v-toolbar>
<v-card-text>
<v-form ref="formRef">
<v-text-field
v-model="data.form.goods_owner_name"
:label="$t('base.ownerOfCargo.goods_owner_name')"
:rules="data.rules.goods_owner_name"
variant="outlined"
></v-text-field>
<v-text-field v-model="data.form.city" :label="$t('base.ownerOfCargo.city')" :rules="data.rules.city" variant="outlined"></v-text-field>
<v-text-field
v-model="data.form.address"
:label="$t('base.ownerOfCargo.address')"
:rules="data.rules.address"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.manager"
:label="$t('base.ownerOfCargo.manager')"
:rules="data.rules.manager"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.contact_tel"
:label="$t('base.ownerOfCargo.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 { OwnerOfCargoVO } from '@/types/Base/OwnerOfCargo'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addOwnerOfCargo, updateOwnerOfCargo } from '@/api/base/ownerOfCargo'
import { StringLength } from '@/utils/dataVerification/formRule'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const props = defineProps<{
showDialog: boolean
form: OwnerOfCargoVO
}>()
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<OwnerOfCargoVO>({
id: 0,
goods_owner_name: '',
city: '',
address: '',
manager: '',
contact_tel: ''
}),
rules: {
goods_owner_name: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.ownerOfCargo.goods_owner_name') }!`,
(val: string) => StringLength(val, 0, 256) === '' || StringLength(val, 0, 256)
],
city: [(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)],
address: [(val: string) => StringLength(val, 0, 256) === '' || StringLength(val, 0, 256)],
manager: [(val: string) => StringLength(val, 0, 64) === '' || StringLength(val, 0, 64)],
contact_tel: [(val: string) => StringLength(val, 0, 64) === '' || StringLength(val, 0, 64)]
}
})
const method = reactive({
closeDialog: () => {
emit('close')
},
submit: async () => {
const { valid } = await formRef.value.validate()
if (valid) {
const { data: res } = dialogTitle.value === 'add' ? await addOwnerOfCargo(data.form) : await updateOwnerOfCargo(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>
[Route("goodsowner")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class GoodsownerController : BaseController
{
#region Args
/// <summary>
/// goodsowner Service
/// </summary>
private readonly IGoodsownerService _goodsownerService;
/// <summary>
/// Localizer Service
/// </summary>
private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
#endregion
#region constructor
/// <summary>
/// constructor
/// </summary>
/// <param name="goodsownerService">goodsowner Service</param>
/// <param name="stringLocalizer">Localizer</param>
public GoodsownerController(
IGoodsownerService goodsownerService
, IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
)
{
this._goodsownerService = goodsownerService;
this._stringLocalizer = stringLocalizer;
}
#endregion
#region Api
/// <summary>
/// page search
/// </summary>
/// <param name="pageSearch">args</param>
/// <returns></returns>
[HttpPost("list")]
public async Task<ResultModel<PageData<GoodsownerViewModel>>> PageAsync(PageSearch pageSearch)
{
var (data, totals) = await _goodsownerService.PageAsync(pageSearch, CurrentUser);
return ResultModel<PageData<GoodsownerViewModel>>.Success(new PageData<GoodsownerViewModel>
{
Rows = data,
Totals = totals
});
}
/// <summary>
/// Get all records
/// </summary>
/// <returns>args</returns>
[HttpGet("all")]
public async Task<ResultModel<List<GoodsownerViewModel>>> GetAllAsync()
{
var data = await _goodsownerService.GetAllAsync(CurrentUser);
if (data.Any())
{
return ResultModel<List<GoodsownerViewModel>>.Success(data);
}
else
{
return ResultModel<List<GoodsownerViewModel>>.Success(new List<GoodsownerViewModel>());
}
}
/// <summary>
/// get a record by id
/// </summary>
/// <returns>args</returns>
[HttpGet]
public async Task<ResultModel<GoodsownerViewModel>> GetAsync(int id)
{
var data = await _goodsownerService.GetAsync(id);
if (data != null && data.id > 0)
{
return ResultModel<GoodsownerViewModel>.Success(data);
}
else
{
return ResultModel<GoodsownerViewModel>.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(GoodsownerViewModel viewModel)
{
var (id, msg) = await _goodsownerService.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(GoodsownerViewModel viewModel)
{
var (flag, msg) = await _goodsownerService.UpdateAsync(viewModel);
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 _goodsownerService.DeleteAsync(id);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
#endregion
#region Import
/// <summary>
/// import goodsowners by excel
/// </summary>
/// <param name="input">excel data</param>
/// <returns></returns>
[HttpPost("excel")]
public async Task<ResultModel<List<GoodsownerImportViewModel>>> ExcelAsync(List<GoodsownerImportViewModel> input)
{
var (flag, errorData) = await _goodsownerService.ExcelAsync(input, CurrentUser);
if (flag)
{
return ResultModel<List<GoodsownerImportViewModel>>.Success(errorData);
}
else
{
return ResultModel<List<GoodsownerImportViewModel>>.Error("", 400, errorData);
}
}
#endregion
}
1、主页面代码
<!-- Freight 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="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="9">
<v-row no-gutters @keyup.enter="method.sureSearch">
<v-col cols="4">
<v-text-field
v-model="data.searchForm.carrier"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.freightSetting.carrier')"
variant="solo"
>
</v-text-field>
</v-col>
<v-col cols="4">
<v-text-field
v-model="data.searchForm.departure_city"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.freightSetting.departure_city')"
variant="solo"
>
</v-text-field>
</v-col>
<v-col cols="4">
<v-text-field
v-model="data.searchForm.arrival_city"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.freightSetting.arrival_city')"
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" :column-config="{ minWidth: '100px' }" :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="carrier" :title="$t('base.freightSetting.carrier')"></vxe-column>
<vxe-column field="departure_city" :title="$t('base.freightSetting.departure_city')"></vxe-column>
<vxe-column field="arrival_city" :title="$t('base.freightSetting.arrival_city')"></vxe-column>
<vxe-column field="price_per_weight" :title="$t('base.freightSetting.price_per_weight')"></vxe-column>
<vxe-column field="price_per_volume" :title="$t('base.freightSetting.price_per_volume')"></vxe-column>
<vxe-column field="min_payment" :title="$t('base.freightSetting.min_payment')"></vxe-column>
<vxe-column field="creator" :title="$t('base.freightSetting.creator')"></vxe-column>
<vxe-column field="create_time" width="170px" :title="$t('base.freightSetting.create_time')"></vxe-column>
<vxe-column field="is_valid" :title="$t('base.freightSetting.is_valid')">
<template #default="{ row, column }">
<span>{{ row[column.property] ? $t('system.combobox.yesOrNo.yes') : $t('system.combobox.yesOrNo.no') }}</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>
<addOrUpdateDialog :show-dialog="data.showDialog" :form="data.dialogForm" @close="method.closeDialog" @saveSuccess="method.saveSuccess" />
<import-table :show-dialog="data.showDialogImport" @close="method.closeDialogImport" @saveSuccess="method.saveSuccessImport" />
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref, reactive, onMounted, watch } from 'vue'
import { VxePagerEvents } from 'vxe-table'
import { computedCardHeight, computedTableHeight, errorColor } from '@/constant/style'
import { FreightVO } from '@/types/Base/Freight'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import { hookComponent } from '@/components/system'
import { deleteFreight, getFreightList } from '@/api/base/freightSetting'
import { DEBOUNCE_TIME } from '@/constant/system'
import { setSearchObject } from '@/utils/common'
import { SearchObject } from '@/types/System/Form'
import tooltipBtn from '@/components/tooltip-btn.vue'
import customPager from '@/components/custom-pager.vue'
import addOrUpdateDialog from './add-or-update-freight.vue'
import importTable from './import-table.vue'
import i18n from '@/languages/i18n'
import { exportData } from '@/utils/exportTable'
const xTable = ref()
const data = reactive({
showDialog: false,
showDialogImport: false,
dialogForm: {
id: 0,
carrier: '',
departure_city: '',
arrival_city: '',
price_per_weight: 0,
price_per_volume: 0,
min_payment: 0,
is_valid: true
},
searchForm: {
carrier: '',
departure_city: '',
arrival_city: ''
},
activeTab: null,
tableData: ref<FreightVO[]>([]),
tablePage: reactive({
total: 0,
pageIndex: 1,
pageSize: DEFAULT_PAGE_SIZE,
searchObjects: ref<Array<SearchObject>>([])
}),
timer: ref<any>(null)
})
const method = reactive({
// Open a dialog to add
add: () => {
data.dialogForm = {
id: 0,
carrier: '',
departure_city: '',
arrival_city: '',
price_per_weight: 0,
price_per_volume: 0,
min_payment: 0,
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()
},
// Import Dialog
openDialogImport: () => {
data.showDialogImport = true
},
closeDialogImport: () => {
data.showDialogImport = false
},
saveSuccessImport: () => {
method.refresh()
method.closeDialogImport()
},
// Refresh data
refresh: () => {
method.getFreightList()
},
getFreightList: async () => {
const { data: res } = await getFreightList(data.tablePage)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.tableData = res.data.rows
data.tablePage.total = res.data.totals
},
editRow(row: FreightVO) {
data.dialogForm = JSON.parse(JSON.stringify(row))
data.showDialog = true
},
deleteRow(row: FreightVO) {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteMessage'),
handleConfirm: async () => {
if (row.id) {
const { data: res } = await deleteFreight(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.getFreightList()
}),
exportTable: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.freightSetting'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
importTable: () => {
const $table = xTable.value
$table.importData()
},
sureSearch: () => {
data.tablePage.searchObjects = setSearchObject(data.searchForm)
method.getFreightList()
}
})
onMounted(() => {
method.getFreightList()
})
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、窗体代码
<!-- Freight 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.freightSetting')}`"></v-toolbar>
<v-card-text>
<v-form ref="formRef">
<v-text-field
v-model="data.form.carrier"
:label="$t('base.freightSetting.carrier')"
:rules="data.rules.carrier"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.departure_city"
:label="$t('base.freightSetting.departure_city')"
:rules="data.rules.departure_city"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.arrival_city"
:label="$t('base.freightSetting.arrival_city')"
:rules="data.rules.arrival_city"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.price_per_weight"
:label="$t('base.freightSetting.price_per_weight')"
:rules="data.rules.price_per_weight"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.price_per_volume"
:label="$t('base.freightSetting.price_per_volume')"
:rules="data.rules.price_per_volume"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.min_payment"
:label="$t('base.freightSetting.min_payment')"
:rules="data.rules.min_payment"
variant="outlined"
></v-text-field>
<v-switch
v-model="data.form.is_valid"
color="primary"
:label="$t('base.freightSetting.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 { addFreight, updateFreight } from '@/api/base/freightSetting'
import { FreightVO } from '@/types/Base/Freight'
import { StringLength, IsDecimal } from '@/utils/dataVerification/formRule'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const props = defineProps<{
showDialog: boolean
form: FreightVO
}>()
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<FreightVO>({
id: 0,
carrier: '',
departure_city: '',
arrival_city: '',
price_per_weight: 0,
price_per_volume: 0,
min_payment: 0,
is_valid: true
}),
rules: {
carrier: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.freightSetting.carrier') }!`,
(val: string) => StringLength(val, 0, 256) === '' || StringLength(val, 0, 256)
],
departure_city: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.freightSetting.departure_city') }!`,
(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)
],
arrival_city: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.freightSetting.arrival_city') }!`,
(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)
],
price_per_weight: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.freightSetting.price_per_weight') }!`,
(val: number) => IsDecimal(val, 'nonNegative', 6, 2) === '' || IsDecimal(val, 'nonNegative', 6, 2)
],
price_per_volume: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.freightSetting.price_per_volume') }!`,
(val: number) => IsDecimal(val, 'nonNegative', 6, 2) === '' || IsDecimal(val, 'nonNegative', 6, 2)
],
min_payment: [
(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.freightSetting.min_payment') }!`,
(val: number) => IsDecimal(val, 'nonNegative', 8, 2) === '' || IsDecimal(val, 'nonNegative', 8, 2)
],
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 addFreight(data.form) : await updateFreight(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>
[Route("freightfee")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class FreightfeeController : BaseController
{
#region Args
/// <summary>
/// freightfee Service
/// </summary>
private readonly IFreightfeeService _freightfeeService;
/// <summary>
/// Localizer Service
/// </summary>
private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
#endregion
#region constructor
/// <summary>
/// constructor
/// </summary>
/// <param name="freightfeeService">freightfee Service</param>
/// <param name="stringLocalizer">Localizer</param>
public FreightfeeController(
IFreightfeeService freightfeeService
, IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
)
{
this._freightfeeService = freightfeeService;
this._stringLocalizer= stringLocalizer;
}
#endregion
#region Api
/// <summary>
/// page search
/// </summary>
/// <param name="pageSearch">args</param>
/// <returns></returns>
[HttpPost("list")]
public async Task<ResultModel<PageData<FreightfeeViewModel>>> PageAsync(PageSearch pageSearch)
{
var (data, totals) = await _freightfeeService.PageAsync(pageSearch, CurrentUser);
return ResultModel<PageData<FreightfeeViewModel>>.Success(new PageData<FreightfeeViewModel>
{
Rows = data,
Totals = totals
});
}
/// <summary>
/// get all records
/// </summary>
/// <returns>args</returns>
[HttpGet("all")]
public async Task<ResultModel<List<FreightfeeViewModel>>> GetAllAsync()
{
var data = await _freightfeeService.GetAllAsync(CurrentUser);
if (data.Any())
{
return ResultModel<List<FreightfeeViewModel>>.Success(data);
}
else
{
return ResultModel<List<FreightfeeViewModel>>.Success(new List<FreightfeeViewModel>());
}
}
/// <summary>
/// get a record by id
/// </summary>
/// <returns>args</returns>
[HttpGet]
public async Task<ResultModel<FreightfeeViewModel>> GetAsync(int id)
{
var data = await _freightfeeService.GetAsync(id);
if (data!=null)
{
return ResultModel<FreightfeeViewModel>.Success(data);
}
else
{
return ResultModel<FreightfeeViewModel>.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(FreightfeeViewModel viewModel)
{
var (id, msg) = await _freightfeeService.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(FreightfeeViewModel viewModel)
{
var (flag, msg) = await _freightfeeService.UpdateAsync(viewModel);
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 _freightfeeService.DeleteAsync(id);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
/// <summary>
/// import freight fee by excel
/// </summary>
/// <param name="excel_datas">excel datas</param>
/// <returns></returns>
[HttpPost("excel")]
public async Task<ResultModel<string>> ExcelAsync(List<FreightfeeExcelmportViewModel> excel_datas)
{
var (flag, msg) = await _freightfeeService.ExcelAsync(excel_datas, CurrentUser);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
#endregion
}
1、主页面代码
<!-- customer 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.customer_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.customer.customer_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="customer_name" :title="$t('base.customer.customer_name')"></vxe-column>
<vxe-column field="city" :title="$t('base.customer.city')"></vxe-column>
<vxe-column field="address" :title="$t('base.customer.address')"></vxe-column>
<vxe-column field="manager" :title="$t('base.customer.manager')"></vxe-column>
<vxe-column field="email" :title="$t('base.customer.email')"></vxe-column>
<vxe-column field="contact_tel" :title="$t('base.customer.contact_tel')"></vxe-column>
<vxe-column field="creator" :title="$t('base.customer.creator')"></vxe-column>
<vxe-column field="create_time" :title="$t('base.customer.create_time')">
<!-- :formatter="['formatDate', 'yyyy-MM-dd HH:mm:ss']" -->
<template #default="{ row, column }">
<span>{{ formatDate(row[column.property]) }}</span>
</template>
</vxe-column>
<vxe-column field="last_update_time" :title="$t('base.customer.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" />
<importCustomerTable :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 { CustomerVO, DataProps } from '@/types/Base/Customer'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import tooltipBtn from '@/components/tooltip-btn.vue'
import addOrUpdateDialog from './add-or-update-customer.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 { getCustomerList, deleteCustomer } from '@/api/base/customer'
import importCustomerTable from './import-customer-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: {
customer_name: ''
},
tableData: [],
// activeTab: null,
showDialog: false,
showDialogImport: false,
dialogForm: {
id: 0,
customer_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,
customer_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: CustomerVO) {
data.dialogForm = JSON.parse(JSON.stringify(row))
data.showDialog = true
},
deleteRow(row: CustomerVO) {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteMessage'),
handleConfirm: async () => {
if (row.id) {
const { data: res } = await deleteCustomer(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.customer'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
getData: async () => {
const { data: res } = await getCustomerList(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.customer')}`"></v-toolbar>
<v-card-text>
<v-form ref="formRef">
<v-text-field
v-model="data.form.customer_name"
:label="$t('base.customer.customer_name')"
:rules="data.rules.customer_name"
variant="outlined"
></v-text-field>
<v-text-field v-model="data.form.city" :label="$t('base.customer.city')" :rules="data.rules.city" variant="outlined"></v-text-field>
<v-text-field
v-model="data.form.email"
:label="$t('base.customer.email')"
:rules="data.rules.email"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.address"
:label="$t('base.customer.address')"
:rules="data.rules.address"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.manager"
:label="$t('base.customer.manager')"
:rules="data.rules.manager"
variant="outlined"
></v-text-field>
<v-text-field
v-model="data.form.contact_tel"
:label="$t('base.customer.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 { CustomerVO } from '@/types/Base/Customer'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addCustomer, updateCustomer } from '@/api/base/customer'
const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])
const props = defineProps<{
showDialog: boolean
form: CustomerVO
}>()
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<CustomerVO>({
id: 0,
customer_name: '',
city: '',
address: '',
manager: '',
email: '',
contact_tel: '',
is_valid: true
}),
rules: {
customer_name: [(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.customer.customer_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 addCustomer(data.form) : await updateCustomer(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>
[Route("customer")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class CustomerController : BaseController
{
#region Args
/// <summary>
/// customer Service
/// </summary>
private readonly ICustomerService _customerService;
/// <summary>
/// Localizer Service
/// </summary>
private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
#endregion
#region constructor
/// <summary>
/// constructor
/// </summary>
/// <param name="customerService">customer Service</param>
/// <param name="stringLocalizer">Localizer</param>
public CustomerController(
ICustomerService customerService
, IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
)
{
this._customerService = customerService;
this._stringLocalizer = stringLocalizer;
}
#endregion
#region Api
/// <summary>
/// page search
/// </summary>
/// <param name="pageSearch">args</param>
/// <returns></returns>
[HttpPost("list")]
public async Task<ResultModel<PageData<CustomerViewModel>>> PageAsync(PageSearch pageSearch)
{
var (data, totals) = await _customerService.PageAsync(pageSearch, CurrentUser);
return ResultModel<PageData<CustomerViewModel>>.Success(new PageData<CustomerViewModel>
{
Rows = data,
Totals = totals
});
}
/// <summary>
/// Get all records
/// </summary>
/// <returns>args</returns>
[HttpGet("all")]
public async Task<ResultModel<List<CustomerViewModel>>> GetAllAsync()
{
var data = await _customerService.GetAllAsync(CurrentUser);
if (data.Any())
{
return ResultModel<List<CustomerViewModel>>.Success(data);
}
else
{
return ResultModel<List<CustomerViewModel>>.Success(new List<CustomerViewModel>());
}
}
/// <summary>
/// get a record by id
/// </summary>
/// <returns>args</returns>
[HttpGet]
public async Task<ResultModel<CustomerViewModel>> GetAsync(int id)
{
var data = await _customerService.GetAsync(id);
if (data != null && data.id > 0)
{
return ResultModel<CustomerViewModel>.Success(data);
}
else
{
return ResultModel<CustomerViewModel>.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(CustomerViewModel viewModel)
{
var (id, msg) = await _customerService.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(CustomerViewModel viewModel)
{
var (flag, msg) = await _customerService.UpdateAsync(viewModel);
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 _customerService.DeleteAsync(id);
if (flag)
{
return ResultModel<string>.Success(msg);
}
else
{
return ResultModel<string>.Error(msg);
}
}
#endregion
#region Import
/// <summary>
/// import customers by excel
/// </summary>
/// <param name="input">excel data</param>
/// <returns></returns>
[HttpPost("excel")]
public async Task<ResultModel<List<CustomerImportViewModel>>> ExcelAsync(List<CustomerImportViewModel> input)
{
var (flag, errorData) = await _customerService.ExcelAsync(input, CurrentUser);
if (flag)
{
return ResultModel<List<CustomerImportViewModel>>.Success(errorData);
}
else
{
return ResultModel<List<CustomerImportViewModel>>.Error("", 400, errorData);
}
}
#endregion
}