文章目录

  • 前言
  • 一、基础设置
    • 1.货主信息
      • 1.1 页面代码
      • 1.2 接口代码
    • 2.运费设置
      • 2.1 页面代码
      • 2.2 接口代码
    • 3.客户信息
      • 3.1 页面代码
      • 3.2 接口代码

前言

基础设置主要分为以下几个模块:

  • 首页
  • 公司信息
  • 角色设置
  • 菜单设置
  • 用户管理
  • 商品类别设置
  • 商品管理
  • 供应商信息
  • 仓库设置
  • 货主信息
  • 运费设置
  • 客户信息


这边需要提下客户和货主的概念:客户是与仓储签订直接合同的甲方,货主是拥有货权的人。

实际情况下,货主会委托某人或某企业管理自己的货物,而这个管理人或企业会与仓储签订合同,使用仓储的软硬件资源。

货主是客户的甲方,客户是仓储的甲方(货主和客户也可能是同一人或企业)。

一、基础设置

1.货主信息

1.1 页面代码

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-fieldv-model="data.searchForm.goods_owner_name"clearablehide-detailsdensity="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 --><divclass="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 infoshowDialog: 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 paginghandlePageChange: ref<VxePagerEvents.PageChange>(({ currentPage, pageSize }) => {data.tablePage.pageIndex = currentPagedata.tablePage.pageSize = pageSizemethod.refresh()}),// Import DialogopenDialogImport: () => {data.showDialogImport = true},closeDialogImport: () => {data.showDialogImport = false},saveSuccessImport: () => {method.refresh()method.closeDialogImport()},sureSearch: () => {data.tablePage.searchObjects = setSearchObject(data.searchForm)method.getOwnerOfCargoList()},// Find Data by PaginationgetOwnerOfCargoList: async () => {const { data: res } = await getOwnerOfCargoByPage(data.tablePage)if (!res.isSuccess) {hookComponent.$message({type: 'error',content: res.errorMessage})return}data.tableData = res.data.rowsdata.tablePage.total = res.data.totals},// Add useradd: () => {data.dialogForm = {id: 0,goods_owner_name: '',city: '',address: '',contact_tel: '',manager: ''}data.showDialog = true},// Shut add or update dialogcloseDialog: () => {data.showDialog = false},// after Add or update success.saveSuccess: () => {method.refresh()method.closeDialog()},// Refresh datarefresh: () => {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 tableexportTable: () => {const $table = xTable.valueexportData({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,() => {// debounceif (data.timer) {clearTimeout(data.timer)}data.timer = setTimeout(() => {data.timer = nullmethod.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-fieldv-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-fieldv-model="data.form.address":label="$t('base.ownerOfCargo.address')":rules="data.rules.address"variant="outlined"></v-text-field><v-text-fieldv-model="data.form.manager":label="$t('base.ownerOfCargo.manager')":rules="data.rules.manager"variant="outlined"></v-text-field><v-text-fieldv-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: booleanform: 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>

1.2 接口代码

[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
}

2.运费设置

2.1 页面代码

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-fieldv-model="data.searchForm.carrier"clearablehide-detailsdensity="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-fieldv-model="data.searchForm.departure_city"clearablehide-detailsdensity="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-fieldv-model="data.searchForm.arrival_city"clearablehide-detailsdensity="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 --><divclass="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 addadd: () => {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 dialogcloseDialog: () => {data.showDialog = false},// After add or update success.saveSuccess: () => {method.refresh()method.closeDialog()},// Import DialogopenDialogImport: () => {data.showDialogImport = true},closeDialogImport: () => {data.showDialogImport = false},saveSuccessImport: () => {method.refresh()method.closeDialogImport()},// Refresh datarefresh: () => {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.rowsdata.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 = currentPagedata.tablePage.pageSize = pageSizemethod.getFreightList()}),exportTable: () => {const $table = xTable.valueexportData({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,() => {// debounceif (data.timer) {clearTimeout(data.timer)}data.timer = setTimeout(() => {data.timer = nullmethod.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-fieldv-model="data.form.carrier":label="$t('base.freightSetting.carrier')":rules="data.rules.carrier"variant="outlined"></v-text-field><v-text-fieldv-model="data.form.departure_city":label="$t('base.freightSetting.departure_city')":rules="data.rules.departure_city"variant="outlined"></v-text-field><v-text-fieldv-model="data.form.arrival_city":label="$t('base.freightSetting.arrival_city')":rules="data.rules.arrival_city"variant="outlined"></v-text-field><v-text-fieldv-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-fieldv-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-fieldv-model="data.form.min_payment":label="$t('base.freightSetting.min_payment')":rules="data.rules.min_payment"variant="outlined"></v-text-field><v-switchv-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: booleanform: 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>

2.2 接口代码

     [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}

3.客户信息

3.1 页面代码

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-fieldv-model="data.searchForm.customer_name"clearablehide-detailsdensity="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 --><divclass="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 DialogopenDialogImport: () => {data.showDialogImport = true},closeDialogImport: () => {data.showDialogImport = false},saveSuccessImport: () => {method.refresh()method.closeDialog()},sureSearch: () => {data.tablePage.searchObjects = setSearchObject(data.searchForm)method.getData()},// Add useradd: () => {data.dialogForm = {id: 0,customer_name: '',city: '',address: '',manager: '',email: '',contact_tel: '',is_valid: true}data.showDialog = true},// Shut add or update dialogcloseDialog: () => {data.showDialog = false},// after Add or update success.saveSuccess: () => {method.refresh()method.closeDialog()},// Refresh datarefresh: () => {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 = currentPagedata.tablePage.pageSize = pageSizemethod.getData()}),exportTable: () => {const $table = xTable.valueexportData({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.rowsdata.tablePage.total = res.data.totals}
})
onMounted(() => {method.getData()
})const cardHeight = computed(() => computedCardHeight({ hasTab: false }))
const tableHeight = computed(() => computedTableHeight({ hasTab: false }))watch(() => data.searchForm,() => {// debounceif (data.timer) {clearTimeout(data.timer)}data.timer = setTimeout(() => {data.timer = nullmethod.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-fieldv-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-fieldv-model="data.form.email":label="$t('base.customer.email')":rules="data.rules.email"variant="outlined"></v-text-field><v-text-fieldv-model="data.form.address":label="$t('base.customer.address')":rules="data.rules.address"variant="outlined"></v-text-field><v-text-fieldv-model="data.form.manager":label="$t('base.customer.manager')":rules="data.rules.manager"variant="outlined"></v-text-field><v-text-fieldv-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: booleanform: 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>

3.2 接口代码

    [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}

【愚公系列】2023年02月 WMS智能仓储系统-015.基础设置(货主信息、运费设置、客户信息)相关推荐

  1. 【愚公系列】2023年02月 WMS智能仓储系统-013.基础设置(首页、公司信息、角色设置)

    文章目录 前言 一.基础设置 1.首页 2.公司信息 2.1 页面代码 2.2 接口代码 3.角色设置 3.1 页面代码 3.2 接口代码 前言 基础设置主要分为以下几个模块: 首页 公司信息 角色设 ...

  2. 【愚公系列】2023年02月 WMS智能仓储系统-011.数据库文档设计

    文章目录 前言 一.数据库文档设计 1.chm版本 2.PDF版本 3.html版本 二.数据库表目录 表结构 __EFMigrationsHistory asn asnsort category c ...

  3. 【愚公系列】2023年02月 WMS智能仓储系统-018.收获管理和发货管理(完结篇)

    文章目录 前言 一.收获管理和发货管理 1.收获管理 1.1 页面代码 1.2 接口代码 2.发货管理 1.1 页面代码 1.2 接口代码 前言 WMS智能仓储收货管理和发货管理是非常重要的两个功能 ...

  4. 【愚公系列】2023年02月 WMS智能仓储系统-007.Swagger接口文档的配置

    文章目录 前言 一.Swagger接口文档的配置 1.安装包 2.注入 2.1 Swagger服务的注入 2.2 appsetting.json的配置 2.3 Swagger服务的封装 2.3.1 S ...

  5. 【愚公系列】2023年02月 WMS智能仓储系统-017.仓内作业(库存冻结、库存调整、库存盘点)

    文章目录 前言 一.仓内作业 1.库存冻结 1.1 页面代码 1.2 接口代码 2.库存调整 2.1 页面代码 2.2 接口代码 3.库存盘点 3.1 页面代码 3.2 接口代码 前言 这节主要分为两 ...

  6. 【愚公系列】2023年02月 WMS智能仓储系统-016.库存管理和仓内作业(库存管理、仓内加工、库存移动)

    文章目录 前言 一.库存管理 1.1 页面代码 1.2 接口代码 二.仓内作业 1.仓内加工 1.1 页面代码 1.2 接口代码 2.库存移动 2.1 页面代码 2.2 接口代码 前言 这节主要分为两 ...

  7. 【愚公系列】2023年02月 WMS智能仓储系统-010.全局过滤、中间件、格式化配置

    文章目录 前言 一.全局过滤 1.全局行为过滤的概念 2.全局行为过滤的注册方式 2.1 方法注册 2.2 控制器注册 2.3 全局注册 2.4 TypeFilter 和 ServiceFilter ...

  8. 【愚公系列】2023年02月 WMS智能仓储系统-001.NLog日志的使用

    文章目录 前言 一.NLog日志的使用 1.安装包 2.配置文件nlog.config 3.使用 前言 系统日志是记录系统中硬件.软件和系统问题的信息,同时还可以监视系统中发生的事件.用户可以通过它来 ...

  9. 【愚公系列】2023年02月 WMS智能仓储系统-012.登录功能的实现

    文章目录 前言 1.业务流程说明 2.登录业务的相关技术点 3.登录-token原理分析 4.前端框架设计 一.登录功能的实现 1.登录页面设计 2.登录逻辑功能实现 2.1 登录逻辑页面 2.2 接 ...

最新文章

  1. ca 自建 颁发证书_openssl自建CA后颁发证书
  2. 苹果在GitHub上正式开源iOS内核源码
  3. CTFshow 文件上传 web157
  4. NoSQL(二):创建、管理集群
  5. boost::geometry::strategy::distance::cross_track用法的测试程序
  6. jQuery 效果 - 动画 animate() 方法
  7. Java Web中相对路径与绝对路径的分析
  8. linux文件服务器迁移方案,服务器之间文件备份方案、如何把服务器文件自动备份到另外一台服务器?...
  9. 两阶段提交与三阶段提交
  10. Excel如何实现随机抽取
  11. SQL - 多表关联
  12. linux如何进入redis客户端,如何在linux下安装redis及客户端的连接
  13. 变量之间的相关性度量
  14. 妹子图kotlin版
  15. java 获取远程服务器信息,java 远程获取服务器信息
  16. tl-wdr5620虚拟服务器设置,TP-Link TL-WDR5620路由器手机怎么设置?
  17. Scrum master成长笔记 –Scrum master最需要的能力
  18. 安卓 微信公众号 默认不操作拦截回退失败
  19. 小红书数据分析工具丨三招教你巧用关键词提高小红书品牌热度
  20. Reflector破译

热门文章

  1. ios项目传到github_使用GitHub Actions将iOS应用程序部署到TestFlight或App Store
  2. 对话系统最新进展-17篇EMNLP 2021论文
  3. 宝塔7.4.2未授权访问漏洞,吃瓜看黑阔删库挂黑页
  4. 做芯片设计需要学编程吗?
  5. Win11通过注册表修改文件默认打开方式
  6. 用一个实例说说委托,匿名委托,Lamda表达式
  7. Bootstrap与AdminLTE
  8. 大数据之MaxWell
  9. 史上最全的 iOS 各种测试工具集锦
  10. python 点到直线的距离