【愚公系列】2023年03月 WMS智能仓储系统-015.基础设置(商品管理、供应商信息、仓库设置)
【摘要】 前言基础设置主要分为以下几个模块:首页公司信息角色设置菜单设置用户管理商品类别设置商品管理供应商信息仓库设置货主信息运费设置客户信息对于商品就要说下SPU和 SKUSPU:SPU(Standard Product Unit):标准化产品单元。是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。通俗点讲,属性值、特性相同的商品就可以称为一个SPU。比...
前言
基础设置主要分为以下几个模块:
- 首页
- 公司信息
- 角色设置
- 菜单设置
- 用户管理
- 商品类别设置
- 商品管理
- 供应商信息
- 仓库设置
- 货主信息
- 运费设置
- 客户信息
对于商品就要说下SPU和 SKU
- SPU:SPU(Standard Product Unit):标准化产品单元。是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。通俗点讲,属性值、特性相同的商品就可以称为一个SPU。比如:
iPhone XS
- SKU:SKU(Stock Keeping Unit)库存量单位,即库存进出计量的单位, 可以是以件、盒、托盘等为单位。SKU是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。比如:
iPhone XS 金色 64g
一、基础设置
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-export-variant" :tooltip-text="$t('system.page.export')" @click="method.exportTable"></tooltip-btn>
</v-col>
<!-- Search Input -->
<v-col cols="12" sm="9">
<v-row no-gutters @keyup.enter="method.sureSearch">
<v-col cols="4">
<v-text-field
v-model="data.searchForm.spu_code"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.commodityManagement.spu_code')"
variant="solo"
>
</v-text-field>
</v-col>
<v-col cols="4">
<v-text-field
v-model="data.searchForm.spu_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.commodityManagement.spu_name')"
variant="solo"
>
</v-text-field>
</v-col>
<v-col cols="4">
<v-text-field
v-model="data.searchForm.category_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.commodityManagement.category_name')"
variant="solo"
>
</v-text-field>
</v-col>
</v-row>
</v-col>
</v-row>
</div>
<!-- Table -->
<div
class="mt-5"
:style="{
height: cardHeight
}"
>
<vxe-table
ref="xTable"
:data="data.tableData"
:column-config="{
minWidth: '100px'
}"
:height="tableHeight"
align="center"
:tree-config="data.tableTreeConfig"
>
<template #empty>
{{ i18n.global.t('system.page.noData') }}
</template>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="spu_code" width="150px" :title="$t('base.commodityManagement.spu_code')" tree-node>
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.sku_code }}</span>
<span v-else>{{ row.spu_code }}</span>
</template>
</vxe-column>
<vxe-column field="spu_name" :title="$t('base.commodityManagement.spu_name')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.sku_name }}</span>
<span v-else>{{ row.spu_name }}</span>
</template>
</vxe-column>
<vxe-column field="category_name" :title="$t('base.commodityManagement.category_name')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.unit }}</span>
<span v-else>{{ row.category_name }}</span>
</template>
</vxe-column>
<vxe-column field="spu_description" :title="$t('base.commodityManagement.spu_description')"> </vxe-column>
<vxe-column field="bar_code" :title="$t('base.commodityManagement.bar_code')"> </vxe-column>
<vxe-column field="supplier_name" :title="$t('base.commodityManagement.supplier_name')"> </vxe-column>
<vxe-column field="brand" :title="$t('base.commodityManagement.brand')"> </vxe-column>
<vxe-column field="weight" :title="$t('base.commodityManagement.weight')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.weight} ${GetUnit('weight', row.weight_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="lenght" :title="$t('base.commodityManagement.lenght')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.lenght} ${GetUnit('length', row.length_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="width" :title="$t('base.commodityManagement.width')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.width} ${GetUnit('length', row.length_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="height" :title="$t('base.commodityManagement.height')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.height} ${GetUnit('length', row.length_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="volume" :title="$t('base.commodityManagement.volume')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ `${row.volume} ${GetUnit('volume', row.volume_unit)}` }}</span>
</template>
</vxe-column>
<vxe-column field="cost" :title="$t('base.commodityManagement.cost')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.cost }}</span>
</template>
</vxe-column>
<vxe-column field="price" :title="$t('base.commodityManagement.price')">
<template #default="{ row }">
<span v-if="row.parent_id > 0">{{ row.price }}</span>
</template>
</vxe-column>
<!-- <vxe-column field="sku_name" :title="$t('base.commodityManagement.sku_name')"></vxe-column> -->
<!-- <vxe-column field="supplier_name" :title="$t('base.commodityManagement.supplier_name')"></vxe-column>
<vxe-column field="brand" :title="$t('base.commodityManagement.brand')"></vxe-column>
<vxe-column field="unit" :title="$t('base.commodityManagement.unit')"></vxe-column>
<vxe-column field="cost" :title="$t('base.commodityManagement.cost')"></vxe-column> -->
<vxe-column field="operate" :title="$t('system.page.operate')" width="160" :resizable="false" show-overflow>
<template #default="{ row }">
<div v-if="!row.parent_id || row.parent_id <= 0">
<tooltip-btn
:flat="true"
icon="mdi-pencil-outline"
:tooltip-text="$t('system.page.edit')"
@click="method.editRow(row)"
></tooltip-btn>
<tooltip-btn
:flat="true"
icon="mdi-delete-outline"
:tooltip-text="$t('system.page.delete')"
:icon-color="errorColor"
@click="method.deleteRow(row)"
></tooltip-btn>
</div>
</template>
</vxe-column>
</vxe-table>
<custom-pager
:current-page="data.tablePage.pageIndex"
:page-size="data.tablePage.pageSize"
perfect
:total="data.tablePage.total"
:page-sizes="PAGE_SIZE"
:layouts="PAGE_LAYOUT"
@page-change="method.handlePageChange"
>
</custom-pager>
</div>
</v-card-text>
</v-card>
</div>
<!-- Add or modify data mode window -->
<addOrUpdateDialog :show-dialog="data.showDialog" :form="data.dialogForm" @close="method.closeDialog" @saveSuccess="method.saveSuccess" />
</div>
</template>
<script lang="ts" setup>
import { computed, reactive, onMounted, ref, watch } from 'vue'
import { VxePagerEvents } from 'vxe-table'
import { computedCardHeight, computedTableHeight, errorColor } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { CommodityVO, DataProps } from '@/types/Base/CommodityManagement'
import { getSpuList, deleteSpu } from '@/api/base/commodityManagementSetting'
import { hookComponent } from '@/components/system'
import addOrUpdateDialog from './add-or-update-commodity.vue'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import i18n from '@/languages/i18n'
import { GetUnit } from '@/constant/commodityManagement'
import customPager from '@/components/custom-pager.vue'
import { setSearchObject } from '@/utils/common'
import { exportData } from '@/utils/exportTable'
import { DEBOUNCE_TIME } from '@/constant/system'
const xTable = ref()
const data: DataProps = reactive({
searchForm: {
spu_code: '',
spu_name: '',
category_name: ''
},
timer: null,
tableData: [],
tablePage: {
total: 0,
pageIndex: 1,
pageSize: DEFAULT_PAGE_SIZE
},
tableTreeConfig: {
transform: true,
rowField: 'tree_id',
parentField: 'parent_id'
},
// Dialog info
showDialog: false,
dialogForm: {
id: 0,
spu_code: '',
spu_name: '',
category_id: 0,
category_name: '',
spu_description: '',
bar_code: '',
supplier_id: 0,
supplier_name: '',
brand: '',
origin: '',
length_unit: 1,
volume_unit: 0,
weight_unit: 1,
detailList: []
}
})
const method = reactive({
sureSearch: () => {
data.tablePage.searchObjects = setSearchObject(data.searchForm)
method.getCompanyList()
},
// Find Data by Pagination
getCompanyList: async () => {
const { data: res } = await getSpuList(data.tablePage)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.tableData = []
for (const item of res.data.rows) {
item.tree_id = item.id
data.tableData.push(item)
for (const ditem of item.detailList) {
ditem.tree_id = 0
ditem.parent_id = item.id
ditem.length_unit = item.length_unit
ditem.volume_unit = item.volume_unit
ditem.weight_unit = item.weight_unit
data.tableData.push(ditem)
}
}
data.tablePage.total = res.data.totals
},
// Add user
add: () => {
data.dialogForm = {
id: 0,
spu_code: '',
spu_name: '',
spu_description: '',
bar_code: '',
brand: '',
length_unit: 1,
volume_unit: 0,
weight_unit: 1,
detailList: []
}
data.showDialog = true
},
// Shut add or update dialog
closeDialog: () => {
data.showDialog = false
},
// after Add or update success.
saveSuccess: () => {
method.refresh()
method.closeDialog()
},
// Refresh data
refresh: () => {
method.getCompanyList()
},
editRow(row: CommodityVO) {
data.dialogForm = JSON.parse(JSON.stringify(row))
data.showDialog = true
},
deleteRow(row: CommodityVO) {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteMessage'),
handleConfirm: async () => {
if (row.id) {
const { data: res } = await deleteSpu(row.id)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.delete') }${ i18n.global.t('system.tips.success') }`
})
method.refresh()
}
}
})
},
// Export table
exportTable: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.commodityManagement'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
// When change paging
handlePageChange: ref<VxePagerEvents.PageChange>(({ currentPage, pageSize }) => {
data.tablePage.pageIndex = currentPage
data.tablePage.pageSize = pageSize
method.refresh()
})
})
onMounted(async () => {
await method.getCompanyList()
})
const cardHeight = computed(() => computedCardHeight({ hasTab: false }))
const tableHeight = computed(() => computedTableHeight({ hasTab: false }))
watch(
() => data.searchForm,
() => {
// debounce
if (data.timer) {
clearTimeout(data.timer)
}
data.timer = setTimeout(() => {
data.timer = null
method.sureSearch()
}, DEBOUNCE_TIME)
},
{
deep: true
}
)
</script>
<style scoped lang="less">
.operateArea {
width: 100%;
min-width: 760px;
display: flex;
align-items: center;
border-radius: 10px;
padding: 0 10px;
}
.col {
display: flex;
align-items: center;
}
</style>
2.供应商信息
2.1 页面代码
1、主页面代码
<!-- supplier Setting -->
<template>
<div class="container">
<div>
<!-- Main Content -->
<v-card class="mt-5">
<v-card-text>
<!-- <v-window v-model="data.activeTab">
<v-window-item> -->
<div class="operateArea">
<v-row no-gutters>
<!-- Operate Btn -->
<v-col cols="12" sm="3" class="col">
<tooltip-btn icon="mdi-plus" :tooltip-text="$t('system.page.add')" @click="method.add()"></tooltip-btn>
<tooltip-btn icon="mdi-refresh" :tooltip-text="$t('system.page.refresh')" @click="method.refresh()"></tooltip-btn>
<tooltip-btn icon="mdi-database-import-outline" :tooltip-text="$t('system.page.import')" @click="method.openDialogImport">
</tooltip-btn>
<tooltip-btn icon="mdi-export-variant" :tooltip-text="$t('system.page.export')" @click="method.exportTable"> </tooltip-btn>
</v-col>
<!-- Search Input -->
<v-col cols="12" sm="9">
<v-row no-gutters @keyup.enter="method.sureSearch">
<v-col cols="12" sm="4"></v-col>
<v-col cols="12" sm="4"></v-col>
<v-col cols="12" sm="4">
<v-text-field
v-model="data.searchForm.supplier_name"
clearable
hide-details
density="comfortable"
class="searchInput ml-5 mt-1"
:label="$t('base.supplier.supplier_name')"
variant="solo"
>
</v-text-field>
</v-col>
</v-row>
</v-col>
</v-row>
</div>
<!-- Table -->
<div
class="mt-5"
:style="{
height: cardHeight
}"
>
<vxe-table ref="xTable" :data="data.tableData" :height="tableHeight" align="center">
<template #empty>
{{ i18n.global.t('system.page.noData') }}
</template>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column type="checkbox" width="50"></vxe-column>
<vxe-column field="supplier_name" :title="$t('base.supplier.supplier_name')"></vxe-column>
<vxe-column field="city" :title="$t('base.supplier.city')"></vxe-column>
<vxe-column field="address" :title="$t('base.supplier.address')"></vxe-column>
<vxe-column field="manager" :title="$t('base.supplier.manager')"></vxe-column>
<vxe-column field="email" :title="$t('base.supplier.email')"></vxe-column>
<vxe-column field="contact_tel" :title="$t('base.supplier.contact_tel')"></vxe-column>
<vxe-column field="creator" :title="$t('base.supplier.creator')"></vxe-column>
<vxe-column field="create_time" :title="$t('base.supplier.create_time')">
<template #default="{ row, column }">
<span>{{ formatDate(row[column.property]) }}</span>
</template>
</vxe-column>
<vxe-column field="last_update_time" :title="$t('base.supplier.last_update_time')">
<template #default="{ row, column }">
<span>{{ formatDate(row[column.property]) }}</span>
</template>
</vxe-column>
<vxe-column field="operate" :title="$t('system.page.operate')" width="160" :resizable="false" show-overflow>
<template #default="{ row }">
<tooltip-btn
:flat="true"
icon="mdi-pencil-outline"
:tooltip-text="$t('system.page.edit')"
@click="method.editRow(row)"
></tooltip-btn>
<tooltip-btn
:flat="true"
icon="mdi-delete-outline"
:tooltip-text="$t('system.page.delete')"
:icon-color="errorColor"
@click="method.deleteRow(row)"
></tooltip-btn>
</template>
</vxe-column>
</vxe-table>
<custom-pager
:current-page="data.tablePage.pageIndex"
:page-size="data.tablePage.pageSize"
perfect
:total="data.tablePage.total"
:page-sizes="PAGE_SIZE"
:layouts="PAGE_LAYOUT"
@page-change="method.handlePageChange"
>
</custom-pager>
</div>
<!-- </v-window-item>
</v-window> -->
</v-card-text>
</v-card>
</div>
</div>
<addOrUpdateDialog :show-dialog="data.showDialog" :form="data.dialogForm" @close="method.closeDialog" @saveSuccess="method.saveSuccess" />
<importSupplierTable :show-dialog="data.showDialogImport" @close="method.closeDialogImport" @saveSuccess="method.saveSuccessImport" />
</template>
<script lang="tsx" setup>
import { computed, ref, reactive, onMounted, watch } from 'vue'
import { VxePagerEvents } from 'vxe-table'
import { computedCardHeight, computedTableHeight, errorColor } from '@/constant/style'
import { SupplierVO, DataProps } from '@/types/Base/Supplier'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import tooltipBtn from '@/components/tooltip-btn.vue'
import addOrUpdateDialog from './add-or-update-supplier.vue'
import { hookComponent } from '@/components/system'
import { DEBOUNCE_TIME } from '@/constant/system'
import { setSearchObject } from '@/utils/common'
import { SearchObject } from '@/types/System/Form'
import i18n from '@/languages/i18n'
import { getSupplierList, deleteSupplier } from '@/api/base/supplier'
import importSupplierTable from './import-supplier-table.vue'
import { formatDate } from '@/utils/format/formatSystem'
import customPager from '@/components/custom-pager.vue'
import { exportData } from '@/utils/exportTable'
const xTable = ref()
const data = reactive({
searchForm: {
supplier_name: ''
},
tableData: [],
// activeTab: null,
showDialog: false,
showDialogImport: false,
dialogForm: {
id: 0,
supplier_name: '',
city: '',
address: '',
manager: '',
email: '',
contact_tel: '',
is_valid: true
},
tablePage: {
total: 0,
pageIndex: 1,
pageSize: DEFAULT_PAGE_SIZE,
searchObjects: ref<Array<SearchObject>>([])
},
timer: ref<any>(null)
})
const method = reactive({
// Import Dialog
openDialogImport: () => {
data.showDialogImport = true
},
closeDialogImport: () => {
data.showDialogImport = false
},
saveSuccessImport: () => {
method.refresh()
method.closeDialog()
},
sureSearch: () => {
data.tablePage.searchObjects = setSearchObject(data.searchForm)
method.getData()
},
// Add user
add: () => {
data.dialogForm = {
id: 0,
supplier_name: '',
city: '',
address: '',
manager: '',
email: '',
contact_tel: '',
is_valid: true
}
data.showDialog = true
},
// Shut add or update dialog
closeDialog: () => {
data.showDialog = false
},
// after Add or update success.
saveSuccess: () => {
method.refresh()
method.closeDialog()
},
// Refresh data
refresh: () => {
method.getData()
},
editRow(row: SupplierVO) {
data.dialogForm = JSON.parse(JSON.stringify(row))
data.showDialog = true
},
deleteRow(row: SupplierVO) {
hookComponent.$dialog({
content: i18n.global.t('system.tips.beforeDeleteMessage'),
handleConfirm: async () => {
if (row.id) {
const { data: res } = await deleteSupplier(row.id)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
hookComponent.$message({
type: 'success',
content: `${ i18n.global.t('system.page.delete') }${ i18n.global.t('system.tips.success') }`
})
method.refresh()
}
}
})
},
handlePageChange: ref<VxePagerEvents.PageChange>(({ currentPage, pageSize }) => {
data.tablePage.pageIndex = currentPage
data.tablePage.pageSize = pageSize
method.getData()
}),
exportTable: () => {
const $table = xTable.value
exportData({
table: $table,
filename: i18n.global.t('router.sideBar.supplier'),
columnFilterMethod({ column }: any) {
return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
}
})
},
getData: async () => {
const { data: res } = await getSupplierList(data.tablePage)
if (!res.isSuccess) {
hookComponent.$message({
type: 'error',
content: res.errorMessage
})
return
}
data.tableData = res.data.rows
data.tablePage.total = res.data.totals
}
})
onMounted(() => {
method.getData()
})
const cardHeight = computed(() => computedCardHeight({ hasTab: false }))
const tableHeight = computed(() => computedTableHeight({ hasTab: false }))
watch(
() => data.searchForm,
() => {
// debounce
if (data.timer) {
clearTimeout(data.timer)
}
data.timer = setTimeout(() => {
data.timer = null
method.sureSearch()
}, DEBOUNCE_TIME)
},
{
deep: true
}
)
</script>
<style scoped lang="less">
.operateArea {
width: 100%;
min-width: 760px;
display: flex;
align-items: center;
border-radius: 10px;
padding: 0 10px;
}
.col {
display: flex;
align-items: center;
}
</style>
3.仓库设置
1、仓库设置
2、库区设置
2、库位设置
3.1 页面代码
1、主页面代码
<!-- Warehouse Setting -->
<template>
<div class="container">
<div>
<v-tabs v-model="data.activeTab" stacked @update:model-value="method.changeTabs">
<v-tab v-for="(item, index) of tabsConfig" :key="index" :value="item.value">
<v-icon>{{ item.icon }}</v-icon>
<p class="tabItemTitle">{{ item.tabName }}</p>
</v-tab>
</v-tabs>
<!-- Main Content -->
<v-card class="mt-5">
<v-card-text>
<v-window v-model="data.activeTab">
<v-window-item value="tabWarehouse">
<tab-warehouse ref="tabWarehouseRef" />
</v-window-item>
<v-window-item value="tabReservoir">
<tab-reservoir ref="tabReservoirRef" />
</v-window-item>
<v-window-item value="tabLocation">
<tab-location ref="tabLocationRef" />
</v-window-item>
</v-window>
</v-card-text>
</v-card>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, watch, nextTick } from 'vue'
import i18n from '@/languages/i18n'
import tabWarehouse from './tab-warehouse.vue'
import tabReservoir from './tab-reservoir.vue'
import tabLocation from './tab-location.vue'
const tabWarehouseRef = ref()
const tabReservoirRef = ref()
const tabLocationRef = ref()
const tabsConfig = [
{
value: 'tabWarehouse',
icon: 'mdi-warehouse',
tabName: i18n.global.t('base.warehouseSetting.warehouseSetting')
},
{
value: 'tabReservoir',
icon: 'mdi-texture-box',
tabName: i18n.global.t('base.warehouseSetting.reservoirSetting')
},
{
value: 'tabLocation',
icon: 'mdi-library-shelves ',
tabName: i18n.global.t('base.warehouseSetting.locationSetting')
}
]
const data = reactive({
activeTab: '',
isLoadWarehouseData: false,
isLoadReservoirData: false,
isLoadLocationData: false
})
const method = reactive({
changeTabs: (e: any): void => {
nextTick(() => {
switch (e) {
case 'tabWarehouse':
// Tips:Must be write the nextTick so that can get DOM!!
if (tabWarehouseRef?.value?.getWarehouseList) {
tabWarehouseRef.value.getWarehouseList()
}
break
case 'tabReservoir':
if (tabReservoirRef?.value?.getWarehouseAreaList) {
tabReservoirRef.value.getWarehouseAreaList()
}
break
case 'tabLocation':
if (tabLocationRef?.value?.getGoodsLocationList) {
tabLocationRef.value.getGoodsLocationList()
}
break
}
})
}
})
onMounted(() => {})
</script>
<style scoped lang="less">
.operateArea {
width: 100%;
min-width: 760px;
display: flex;
align-items: center;
border-radius: 10px;
padding: 0 10px;
}
.col {
display: flex;
align-items: center;
}
</style>
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)