前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【愚公系列】2023年02月 WMS智能仓储系统-014.基础设置(菜单设置、用户管理、商品类别设置)

【愚公系列】2023年02月 WMS智能仓储系统-014.基础设置(菜单设置、用户管理、商品类别设置)

作者头像
愚公搬代码
发布2023-03-16 17:18:59
发布2023-03-16 17:18:59
62700
代码可运行
举报
文章被收录于专栏:历史专栏历史专栏
运行总次数:0
代码可运行

文章目录


前言

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

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

一、基础设置

1.菜单设置

这边菜单是写死的,因为只是WMS需要的不多。

1.1 页面代码

1、主页面代码

代码语言:javascript
代码运行次数:0
复制
<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-pencil-outline" :tooltip-text="$t('system.page.edit')" @click="method.editForm()"></tooltip-btn>
                <tooltip-btn icon="mdi-delete-outline" :tooltip-text="$t('system.page.delete')" @click="method.deleteForm()"></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="12" sm="4">
                    <v-text-field
                      v-model="data.searchForm.userName"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('login.userName')"
                      variant="solo"
                    >
                    </v-text-field>
                  </v-col>
                  <v-col cols="12" sm="4">
                    <v-text-field
                      v-model="data.searchForm.userName1"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('login.userName')"
                      variant="solo"
                    >
                    </v-text-field>
                  </v-col>
                  <v-col cols="12" sm="4">
                    <v-text-field
                      v-model="data.searchForm.userName2"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('login.userName')"
                      variant="solo"
                    >
                    </v-text-field>
                  </v-col>
                </v-row> -->
              </v-col>
            </v-row>
          </div>

          <!-- Table -->
          <div
            class="mt-5"
            :style="{
              height: cardHeight
            }"
          >
            <v-row :no-gutters="true">
              <v-col :cols="3" class="dataListCol">
                <v-card :height="tableHeight">
                  <NavListVue
                    :list-data="data.roleList"
                    :title="data.navListOptions.title"
                    :label-key="data.navListOptions.labelKey"
                    :index-key="data.navListOptions.indexKey"
                    :index-value="data.navListOptions.indexValue"
                    @item-click="method.navListClick"
                  />
                </v-card>
              </v-col>
              <v-col :cols="9">
                <vxe-table ref="xTable" :data="data.activeRoleMenuForm.detailList" :height="tableHeight" align="center">
                  <template #empty>
                    {{ i18n.global.t('system.page.noData') }}
                  </template>
                  <vxe-column type="seq" width="60"></vxe-column>
                  <vxe-column field="menu_name" :title="$t('base.roleMenu.menu_name')">
                    <template #default="{ row }">
                      <span>{{ $t(`router.sideBar.${row.menu_name}`) }}</span>
                    </template>
                  </vxe-column>
                </vxe-table>
              </v-col>
            </v-row>
          </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 } from 'vue'
import { computedCardHeight, computedTableHeight } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { DataProps, RoleMenuVO } from '@/types/Base/RoleMenu'
import { getRoleMenuAll, getRoleMenuById, deleteRoleMenu } from '@/api/base/roleMenu'
import { hookComponent } from '@/components/system'
import addOrUpdateDialog from './add-or-update-role-menu.vue'
import i18n from '@/languages/i18n'
import NavListVue from '@/components/page/nav-list.vue'
import { exportData } from '@/utils/exportTable'

const xTable = ref()

const data: DataProps = reactive({
  navListOptions: {
    title: i18n.global.t('base.roleMenu.role_name'),
    labelKey: 'role_name',
    indexKey: 'userrole_id',
    indexValue: ''
  },
  // Activation id
  activeRoleMenuForm: {
    userrole_id: 0,
    role_name: '',
    detailList: []
  },
  // searchForm: {
  //   userName: '',
  //   userName1: '',
  //   userName2: ''
  // },
  roleList: [],
  // Dialog info
  showDialog: false,
  dialogForm: {
    detailList: []
  }
})

const method = reactive({
  sureSearch: () => {
    // console.log(data.searchForm)
  },
  // Find Data by Pagination
  getCompanyList: async () => {
    // Clear detailed data before refreshing
    method.clearDialogForm()
    const { data: res } = await getRoleMenuAll()
    if (!res.isSuccess) {
      hookComponent.$message({
        type: 'error',
        content: res.errorMessage
      })
      return
    }
    data.roleList = res.data
    if (data.roleList.findIndex((item) => item.userrole_id === data.activeRoleMenuForm.userrole_id) > -1 && data.activeRoleMenuForm.userrole_id) {
      method.getRoleMenus(data.activeRoleMenuForm.userrole_id)
    } else if (data.roleList.length > 0) {
      method.navListClick(data.roleList[0])
    } else {
      data.activeRoleMenuForm = {
        userrole_id: 0,
        role_name: '',
        detailList: []
      }
    }
  },
  // Add user
  add: () => {
    method.clearDialogForm()
    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()
  },
  editForm() {
    if (!data.activeRoleMenuForm.userrole_id) {
      hookComponent.$message({
        type: 'error',
        content: i18n.global.t('base.roleMenu.beforeUpdateOrDel')
      })
      return
    }
    data.dialogForm = JSON.parse(JSON.stringify(data.activeRoleMenuForm))
    // Delete rowid of existing data
    for (const item of data.dialogForm.detailList) {
      if (item._X_ROW_KEY) {
        delete item._X_ROW_KEY
      }
    }
    data.showDialog = true
  },
  deleteForm() {
    if (!data.activeRoleMenuForm.userrole_id) {
      hookComponent.$message({
        type: 'error',
        content: i18n.global.t('base.roleMenu.beforeUpdateOrDel')
      })
      return
    }
    const row = data.activeRoleMenuForm
    hookComponent.$dialog({
      content: i18n.global.t('system.tips.beforeDeleteMessage'),
      handleConfirm: async () => {
        if (row.userrole_id) {
          const { data: res } = await deleteRoleMenu(row.userrole_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.roleMenu'),
      columnFilterMethod({ column }: any) {
        return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
      }
    })
  },
  // Get detailed data
  getRoleMenus: async (userrole_id: number) => {
    const { data: res } = await getRoleMenuById(userrole_id)
    if (!res.isSuccess) {
      hookComponent.$message({
        type: 'error',
        content: res.errorMessage
      })
      return
    }
    data.activeRoleMenuForm = res.data
  },
  // Refresh dialog data
  clearDialogForm: () => {
    data.dialogForm = {
      detailList: []
    }
  },
  // Click navList
  navListClick: (item: RoleMenuVO) => {
    if (!item.userrole_id) {
      return
    }
    data.navListOptions.indexValue = String(item.userrole_id)
    method.getRoleMenus(item.userrole_id)
  }
})

onMounted(async () => {
  await method.getCompanyList()
})

const cardHeight = computed(() => computedCardHeight({ hasTab: false }))

const tableHeight = computed(() => computedTableHeight({ hasTab: false, hasPager: false }))
</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;
}
// Adjust the spacing between lists and tables
.dataListCol {
  box-sizing: border-box;
  padding-right: 10px !important;
}
.roleNameCol {
  width: 100%;
  height: 100%;
  cursor: pointer;
  // &:hover: {
  //   background-color: #9156fd;
  // }
}
.roleNameCol:hover {
  background-color: #9156fd;
  color: white;
}
.activeRow {
  background-color: #9156fd;
}
</style>

2、窗体代码

代码语言:javascript
代码运行次数:0
复制
<template>
  <v-dialog v-model="isShow" :width="'30%'" transition="dialog-top-transition" :persistent="true">
    <template #default>
      <v-card class="formCard">
        <v-toolbar color="white" :title="`${$t('router.sideBar.roleMenu')}`"></v-toolbar>
        <v-card-text>
          <v-form ref="formRef">
            <v-select
              v-model="data.form.userrole_id"
              :items="data.combobox.role_name"
              item-title="label"
              item-value="value"
              :rules="data.rules.role_name"
              :label="$t('base.roleMenu.role_name')"
              variant="outlined"
              clearable
            ></v-select>
            <v-select
              v-model="data.menusSelectedList"
              :items="data.combobox.menu_name"
              :menu-props="{ maxHeight: 400 }"
              item-title="label"
              item-value="value"
              :label="$t('base.roleMenu.menu_name')"
              variant="outlined"
              chips
              multiple
              clearable
            >
            </v-select>
          </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 { RoleMenuVO, RoleMenuDetailVo } from '@/types/Base/RoleMenu'
import { UserRoleVO } from '@/types/Base/UserRoleSetting'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addRoleMenu, updateRoleMenu, getMenus } from '@/api/base/roleMenu'
import { getUserRoleAll } from '@/api/base/userRoleSetting'
import { MenuItem } from '@/types/System/Store'

const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])

const props = defineProps<{
  showDialog: boolean
  form: RoleMenuVO
}>()

const isShow = computed(() => props.showDialog)

const data = reactive({
  dialogTitle: '',
  form: ref<RoleMenuVO>({
    userrole_id: 0,
    role_name: '',
    detailList: []
  }),
  // Multiple drop-down box values, mainly used to temporarily save the selected values
  menusSelectedList: ref<any[]>([]),
  // If it is modified, you need to pass a negative ID to the API to delete the existing details
  removeDetailList: ref<RoleMenuDetailVo[]>([]),
  // Drop down box options
  combobox: ref<{
    role_name: {
      label: string
      value: number
    }[]
    menu_name: {
      label: string
      value: number
    }[]
  }>({
    role_name: [],
    menu_name: []
  }),
  rules: {
    role_name: [(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.roleMenu.role_name') }!`],
    menu_name: [(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.roleMenu.menu_name') }!`]
  }
})

const method = reactive({
  // Get dialog type, add or update
  getDialogType: () => {
    // This is special because this document is not actually a table,
    // but the data associated with another table.
    // so directly use the details to determine whether it is a new document
    if (props.form.detailList.length > 0) {
      data.dialogTitle = 'update'
    } else {
      data.dialogTitle = 'add'
    }
  },
  // Get the options required by the drop-down box
  getCombobox: async () => {
    data.combobox.role_name = []
    const { data: res } = await getUserRoleAll()
    if (!res.isSuccess) {
      return
    }
    const roleNameList: UserRoleVO[] = res.data
    for (const role of roleNameList) {
      data.combobox.role_name.push({
        label: role.role_name,
        value: role.id
      })
    }
    data.combobox.menu_name = []
    const { data: menuRes } = await getMenus()
    if (!menuRes.isSuccess) {
      return
    }
    const menus: MenuItem[] = menuRes.data
    for (const menu of menus) {
      data.combobox.menu_name.push({
        label: i18n.global.t(`router.sideBar.${ menu.menu_name }`),
        value: menu.id
      })
    }
  },
  closeDialog: () => {
    emit('close')
  },
  // Details verification before document submission
  beforeSubmit: (): boolean => {
    let flag = true
    // Process the new dropdown options
    for (const item of data.menusSelectedList) {
      if (data.form.detailList.findIndex((dl) => dl.menu_id === item) < 0) {
        data.form.detailList.push({
          id: 0,
          menu_id: item
        })
      }
    }
    if (data.dialogTitle === 'update') {
      for (const item of data.form.detailList) {
        if (!data.menusSelectedList.includes(item.menu_id)) {
          // Delete if ID is negative
          item.id = -item.id
        }
      }
    }
    if (data.form.detailList.length === 0) {
      hookComponent.$message({
        type: 'error',
        content: i18n.global.t('system.tips.detailLengthIsZero')
      })
      flag = false
    }
    return flag
  },
  submit: async () => {
    const beforeSubmitFlag = method.beforeSubmit()
    if (!beforeSubmitFlag) {
      return
    }
    const { valid } = await formRef.value.validate()
    if (valid) {
      const { data: res } = data.dialogTitle === 'add'
          ? await addRoleMenu(data.form)
          : await updateRoleMenu({ ...data.form, detailList: [...data.form.detailList, ...data.removeDetailList] }) // Merge the deleted list and the original list
      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.getDialogType()
      method.getCombobox()
      data.form = props.form
      data.menusSelectedList = data.form.detailList.map((item) => item.menu_id)
    }
  }
)
</script>

<style scoped lang="less">
</style>

1.2 接口代码

代码语言:javascript
代码运行次数:0
复制
/// <summary>
/// rolemenu controller
/// </summary>
[Route("rolemenu")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class RolemenuController : BaseController
{
    #region Args

    /// <summary>
    /// rolemenu Service
    /// </summary>
    private readonly IRolemenuService _rolemenuService;

    /// <summary>
    /// Localizer Service
    /// </summary>
    private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
    #endregion

    #region constructor
    /// <summary>
    /// constructor
    /// </summary>
    /// <param name="rolemenuService">rolemenu Service</param>
    /// <param name="stringLocalizer">Localizer</param>
    public RolemenuController(
        IRolemenuService rolemenuService
      , IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
        )
    {
        this._rolemenuService = rolemenuService;
        this._stringLocalizer = stringLocalizer;
    }
    #endregion

    #region Api
    /// <summary>
    /// 通过角色ID获取菜单
    /// </summary>
    /// <param name="userrole_id">user role id</param>
    /// <returns></returns>
    [HttpGet("authority")]
    public async  Task<ResultModel<List<MenuViewModel>>> GetMenusByRoleId(int userrole_id)
    {
        var data = await _rolemenuService.GetMenusByRoleId(userrole_id);
        if (data.Any())
        {
            return ResultModel<List<MenuViewModel>>.Success(data);
        }
        else
        {
            return ResultModel<List<MenuViewModel>>.Success(new List<MenuViewModel>());
        }
    }
    /// <summary>
    /// get all records
    /// </summary>
    /// <returns>args</returns>
    [HttpGet("all")]
    public async Task<ResultModel<List<RolemenuListViewModel>>> GetAllAsync()
    {
        var data = await _rolemenuService.GetAllAsync(CurrentUser);
        if (data.Any())
        {
            return ResultModel<List<RolemenuListViewModel>>.Success(data);
        }
        else
        {
            return ResultModel<List<RolemenuListViewModel>>.Success(new List<RolemenuListViewModel>());
        }
    }
    /// <summary>
    /// Get all menus
    /// </summary>
    /// <returns></returns>
    [HttpGet("menus")]
    public async Task<ResultModel<List<MenuViewModel>>> GetAllMenusAsync()
    {
        var data = await _rolemenuService.GetAllMenusAsync(CurrentUser);
        if (data.Any())
        {
            return ResultModel<List<MenuViewModel>>.Success(data);
        }
        else
        {
            return ResultModel<List<MenuViewModel>>.Success(new List<MenuViewModel>());
        }
    }
    /// <summary>
    /// get a record by id
    /// </summary>
    /// <returns>args</returns>
    [HttpGet]
    public async Task<ResultModel<RolemenuBothViewModel>> GetAsync(int userrole_id)
    {
        var data = await _rolemenuService.GetAsync(userrole_id);
        if (data != null && data.userrole_id > 0)
        {
            return ResultModel<RolemenuBothViewModel>.Success(data);
        }
        else
        {
            return ResultModel<RolemenuBothViewModel>.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(RolemenuBothViewModel viewModel)
    {
        var (id, msg) = await _rolemenuService.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(RolemenuBothViewModel viewModel)
    {
        var (flag, msg) = await _rolemenuService.UpdateAsync(viewModel, CurrentUser);
        if (flag)
        {
            return ResultModel<bool>.Success(flag);
        }
        else
        {
            return ResultModel<bool>.Error(msg, 400, flag);
        }
    }

    /// <summary>
    /// delete a record
    /// </summary>
    /// <param name="userrole_id">userrole id</param>
    /// <returns></returns>
    [HttpDelete]
    public async Task<ResultModel<string>> DeleteAsync(int userrole_id)
    {
        var (flag, msg) = await _rolemenuService.DeleteAsync(userrole_id);
        if (flag)
        {
            return ResultModel<string>.Success(msg);
        }
        else
        {
            return ResultModel<string>.Error(msg);
        }
    }
    #endregion

}

2.用户管理

2.1 页面代码

1、主页面代码

代码语言:javascript
代码运行次数:0
复制
<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>
                <tooltip-btn icon="mdi-lock-reset" :tooltip-text="$t('base.userManagement.restPwd')" @click="method.restPwd"></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.user_num"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('base.userManagement.user_num')"
                      variant="solo"
                    >
                    </v-text-field>
                  </v-col>
                  <v-col cols="4">
                    <v-text-field
                      v-model="data.searchForm.user_name"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('base.userManagement.user_name')"
                      variant="solo"
                    >
                    </v-text-field>
                  </v-col>
                  <v-col cols="4">
                    <v-text-field
                      v-model="data.searchForm.user_role"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('base.userManagement.user_role')"
                      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="user_num" :title="$t('base.userManagement.user_num')"></vxe-column>
              <vxe-column field="user_name" :title="$t('base.userManagement.user_name')"></vxe-column>
              <vxe-column field="user_role" :title="$t('base.userManagement.user_role')"></vxe-column>
              <vxe-column field="sex" :title="$t('base.userManagement.sex')">
                <template #default="{ row }">
                  <span>{{ $t(`system.combobox.sex.${row.sex}`) }}</span>
                </template>
              </vxe-column>
              <vxe-column field="contact_tel" :title="$t('base.userManagement.contact_tel')"></vxe-column>
              <vxe-column field="is_valid" :title="$t('base.userManagement.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>
            <!-- <vxe-grid v-bind="data.gridOptions">
              <template #pager>
                <custom-pagerr
                  v-model:current-page="data.tablePage.pageIndex"
                  v-model:page-size="data.tablePage.pageSize"
                  :layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
                  :total="data.tablePage.total"
                  @page-change="handlePageChange"
                >
                </custom-pagerr>
              </template>
            </vxe-grid> -->
          </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 { DataProps, UserVO } from '@/types/Base/UserManagement'
import { getUserList, deleteUser, resetPassword } from '@/api/base/userManagement'
import { hookComponent } from '@/components/system'
import addOrUpdateDialog from './add-or-update-user.vue'
import { PAGE_SIZE, PAGE_LAYOUT, DEFAULT_PAGE_SIZE } from '@/constant/vxeTable'
import i18n from '@/languages/i18n'
import customPager from '@/components/custom-pager.vue'
import { setSearchObject } from '@/utils/common'
import importTable from './import-table.vue'
import { exportData } from '@/utils/exportTable'
import { DEBOUNCE_TIME } from '@/constant/system'

const xTable = ref()

const data: DataProps = reactive({
  showDialogImport: false,
  searchForm: {
    user_num: '',
    user_name: '',
    user_role: ''
  },
  timer: null,
  tableData: [],
  tablePage: {
    total: 0,
    pageIndex: 1,
    pageSize: DEFAULT_PAGE_SIZE
  },
  // Dialog info
  showDialog: false,
  dialogForm: {
    id: 0,
    user_num: '',
    user_name: '',
    contact_tel: '',
    auth_string: '',
    is_valid: true
  }
})

const method = reactive({
  // Import Dialog
  openDialogImport: () => {
    data.showDialogImport = true
  },
  closeDialogImport: () => {
    data.showDialogImport = false
  },
  saveSuccessImport: () => {
    method.refresh()
    method.closeDialogImport()
  },
  sureSearch: () => {
    data.tablePage.searchObjects = setSearchObject(data.searchForm)
    method.getUserList()
  },
  // Find Data by Pagination
  getUserList: async () => {
    const { data: res } = await getUserList(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,
      user_num: '',
      user_name: '',
      contact_tel: '',
      auth_string: '',
      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.getUserList()
  },
  editRow(row: UserVO) {
    data.dialogForm = JSON.parse(JSON.stringify(row))
    data.showDialog = true
  },
  deleteRow(row: UserVO) {
    hookComponent.$dialog({
      content: i18n.global.t('system.tips.beforeDeleteMessage'),
      handleConfirm: async () => {
        if (row.id) {
          const { data: res } = await deleteUser(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()
        }
      }
    })
  },
  // When change paging
  handlePageChange: ref<VxePagerEvents.PageChange>(({ currentPage, pageSize }) => {
    data.tablePage.pageIndex = currentPage
    data.tablePage.pageSize = pageSize
    method.refresh()
  }),
  // Export table
  exportTable: () => {
    const $table = xTable.value
    exportData({
      table: $table,
      filename: i18n.global.t('router.sideBar.userManagement'),
      columnFilterMethod({ column }: any) {
        return !['checkbox'].includes(column?.type) && !['operate'].includes(column?.field)
      }
    })
  },
  // Reset password
  restPwd: async () => {
    const checkRecord: UserVO[] = xTable.value.getCheckboxRecords(true)
    if (checkRecord.length > 0) {
      hookComponent.$dialog({
        content: i18n.global.t('base.userManagement.beforeResetPwd'),
        handleConfirm: async () => {
          const idList = checkRecord.map((item) => item.id)
          const { data: res } = await resetPassword(idList)
          if (!res.isSuccess) {
            hookComponent.$message({
              type: 'error',
              content: res.errorMessage
            })
            return
          }
          hookComponent.$dialog({
            content: `${ i18n.global.t('base.userManagement.afterResetPwd') } ${ res.data }`
          })
        }
      })
    } else {
      hookComponent.$message({
        type: 'error',
        content: i18n.global.t('base.userManagement.checkboxIsNull')
      })
    }
  }
})

onMounted(async () => {
  await method.getUserList()
})

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、窗体代码

代码语言:javascript
代码运行次数:0
复制
<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.userManagement')}`"></v-toolbar>
        <v-card-text>
          <v-form ref="formRef">
            <v-text-field
              v-model="data.form.user_num"
              :label="$t('base.userManagement.user_num')"
              :rules="data.rules.user_num"
              variant="outlined"
            ></v-text-field>
            <v-text-field
              v-model="data.form.user_name"
              :label="$t('base.userManagement.user_name')"
              :rules="data.rules.user_name"
              variant="outlined"
            ></v-text-field>
            <v-select
              v-model="data.form.user_role"
              :items="data.combobox.user_role"
              :rules="data.rules.user_role"
              :label="$t('base.userManagement.user_role')"
              variant="outlined"
              clearable
            ></v-select>
            <v-select
              v-model="data.form.sex"
              :items="data.combobox.sex"
              item-title="label"
              item-value="value"
              :rules="data.rules.sex"
              :label="$t('base.userManagement.sex')"
              variant="outlined"
              clearable
            ></v-select>
            <v-text-field
              v-model="data.form.contact_tel"
              :label="$t('base.userManagement.contact_tel')"
              :rules="data.rules.contact_tel"
              variant="outlined"
            ></v-text-field>
            <v-switch
              v-model="data.form.is_valid"
              color="primary"
              :label="$t('base.userManagement.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 { UserVO } from '@/types/Base/UserManagement'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addUser, updateUser, getSelectItem } from '@/api/base/userManagement'
import { StringLength } from '@/utils/dataVerification/formRule'

const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])

const props = defineProps<{
  showDialog: boolean
  form: UserVO
}>()

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<UserVO>({
    id: 0,
    user_num: '',
    user_name: '',
    contact_tel: '',
    is_valid: true
  }),
  rules: {
    user_num: [
      (val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.userManagement.user_num') }!`,
      (val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)
    ],
    user_name: [
      (val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.userManagement.user_name') }!`,
      (val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 128)
    ],
    user_role: [(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.userManagement.user_role') }!`],
    sex: [(val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.userManagement.sex') }!`],
    contact_tel: [(val: string) => StringLength(val, 0, 128) === '' || StringLength(val, 0, 64)],
    is_valid: []
  },
  combobox: ref<{
    sex: {
      label: string
      value: string
    }[]
    user_role: string[]
  }>({
    sex: [],
    user_role: []
  })
})

const method = reactive({
  // Get the options required by the drop-down box
  getCombobox: async () => {
    // Static drop-down box
    const sexOptions = ['male', 'female']
    data.combobox.sex = []
    for (const sex of sexOptions) {
      data.combobox.sex.push({
        label: i18n.global.t(`system.combobox.sex.${ sex }`),
        value: sex
      })
    }
    // Dynamic drop-down box
    data.combobox.user_role = []
    const { data: res } = await getSelectItem()
    if (!res.isSuccess) {
      return
    }
    for (const item of res.data) {
      switch (item.code) {
        case 'user_role':
          data.combobox.user_role.push(item.name)
          break
      }
    }
  },
  closeDialog: () => {
    emit('close')
  },
  submit: async () => {
    const { valid } = await formRef.value.validate()
    if (valid) {
      const { data: res } = dialogTitle.value === 'add' ? await addUser(data.form) : await updateUser(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.getCombobox()
      data.form = props.form
    }
  }
)
</script>

<style scoped lang="less">
.v-form {
  div {
    margin-bottom: 7px;
  }
}
</style>
代码语言:javascript
代码运行次数:0
复制
<!-- UserManagement Setting Import Dialog -->
<template>
  <v-dialog v-model="isShow" width="70%" transition="dialog-top-transition" :persistent="true">
    <template #default>
      <v-card>
        <v-toolbar color="white" :title="`${$t('system.page.import')}`"></v-toolbar>
        <v-card-text>
          <div class="mb-4">
            <tooltip-btn icon="mdi-plus" :tooltip-text="$t('system.page.chooseFile')" size="x-small" @click="method.chooseFile"></tooltip-btn>
            <tooltip-btn
              icon="mdi-export-variant"
              :tooltip-text="$t('system.page.exportTemplate')"
              size="x-small"
              @click="method.exportTemplate"
            ></tooltip-btn>
            <input v-show="false" id="open" ref="uploadExcel" type="file" accept=".xls, .xlsx" @change="method.readExcel" />
          </div>
          <vxe-table
            ref="xTable"
            :column-config="{ minWidth: '100px' }"
            :data="data.importData"
            :height="SYSTEM_HEIGHT.SELECT_TABLE"
            :edit-config="{ trigger: 'click', mode: 'cell' }"
            :edit-rules="data.validRules"
            :export-config="{}"
            align="center"
          >
            <template #empty>
              {{ i18n.global.t('system.page.noData') }}
            </template>
            <vxe-column type="seq" width="60"></vxe-column>
            <vxe-column field="operate" width="60" :title="$t('system.page.operate')" :resizable="false">
              <template #default="{ row }">
                <tooltip-btn
                  :flat="true"
                  icon="mdi-delete-outline"
                  :tooltip-text="$t('system.page.delete')"
                  :icon-color="errorColor"
                  @click="method.deleteRow(row)"
                ></tooltip-btn>
              </template>
            </vxe-column>
            <vxe-column field="user_num" :title="$t('base.userManagement.user_num')"></vxe-column>
            <vxe-column field="user_name" :title="$t('base.userManagement.user_name')"></vxe-column>
            <vxe-column field="contact_tel" :title="$t('base.userManagement.contact_tel')"></vxe-column>
            <vxe-column field="user_role" :title="$t('base.userManagement.user_role')"></vxe-column>
            <vxe-column field="sex" :title="$t('base.userManagement.sex')"></vxe-column>
          </vxe-table>
        </v-card-text>
        <v-card-actions class="justify-end">
          <v-btn variant="text" @click="method.closeDialog">{{ $t('system.page.close') }}</v-btn>
          <v-btn color="primary" variant="text" @click="method.submit">{{ $t('system.page.submit') }}</v-btn>
        </v-card-actions>
      </v-card>
    </template>
  </v-dialog>
</template>

<script lang="ts" setup>
import { reactive, computed, ref, watch } from 'vue'
import { VxeTablePropTypes } from 'vxe-table'
import * as XLSX from 'xlsx'
import i18n from '@/languages/i18n'
import { excelImport } from '@/api/base/userManagement'
import { hookComponent } from '@/components/system/index'
import { SYSTEM_HEIGHT, errorColor } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { ImportVO } from '@/types/Base/UserManagement'
import { exportData } from '@/utils/exportTable'
import { formatString } from '@/utils/format/formatSystem'

const emit = defineEmits(['close', 'saveSuccess'])
const uploadExcel = ref()
const xTable = ref()

const props = defineProps<{
  showDialog: boolean
}>()

const isShow = computed(() => props.showDialog)

const data = reactive({
  importData: ref<Array<ImportVO>>([]),
  validRules: ref<VxeTablePropTypes.EditRules>({})
})

const method = reactive({
  initForm: () => {
    data.importData = []
  },
  closeDialog: () => {
    emit('close')
  },
  submit: async () => {
    const isValid = method.valid()
    if (!isValid) {
      return
    }

    const $table = xTable.value
    // It must be use 'getTableData()' to get all datas with table because it will delete row sometimes.
    const importData = JSON.parse(JSON.stringify($table.getTableData().fullData))
    for (const item of importData) {
      let sex = 'male'
      if (['男', '女', 'Male', 'Female'].includes(item.sex)) {
        switch (item.sex) {
          case '男':
          case 'Male':
            sex = 'male'
            break
          case '女':
          case 'Female':
            sex = 'female'
            break
        }
      }
      item.sex = sex
    }
    const { data: res } = await excelImport(importData)
    if (!res.isSuccess) {
      hookComponent.$message({
        type: 'error',
        content: res.errorMessage
      })
      return
    }
    hookComponent.$message({
      type: 'success',
      content: `${ i18n.global.t('system.page.submit') }${ i18n.global.t('system.tips.success') }`
    })
    emit('saveSuccess')
  },

  valid: () => {
    const $table = xTable.value
    const importData = $table.getTableData().fullData

    if (importData.length <= 0) {
      hookComponent.$message({
        type: 'error',
        content: `${ i18n.global.t('system.tips.detailLengthIsZero') }`
      })
      return false
    }
    return true
  },

  chooseFile: async () => {
    uploadExcel.value.value = ''
    uploadExcel.value.click()
  },

  readExcel: async (evnt: any) => {
    const files = evnt.target.files
    if (files.length <= 0) {
      return false
    }

    const file = files[0]
    const fileReader = new FileReader()

    fileReader.onload = (ev: ProgressEvent<FileReader>) => {
      const fileData = ev?.target?.result
      if (fileData) {
        const workbook = XLSX.read(fileData, { type: 'binary' })
        const wsname = workbook.SheetNames[0]

        let ws = XLSX.utils.sheet_to_json(workbook.Sheets[wsname])
        let str = JSON.stringify(ws)
        str = str.replace(/(/g, '(')
        str = str.replace(/)/g, ')')
        ws = JSON.parse(str)

        data.importData = []
        ws.forEach((value: any, index: number, ws: any) => {
          data.importData.push({
            user_num: formatString(ws[index][i18n.global.t('base.userManagement.user_num')]),
            user_name: formatString(ws[index][i18n.global.t('base.userManagement.user_name')]),
            contact_tel: formatString(ws[index][i18n.global.t('base.userManagement.contact_tel')]),
            user_role: formatString(ws[index][i18n.global.t('base.userManagement.user_role')]),
            sex: formatString(ws[index][i18n.global.t('base.userManagement.sex')]),
            is_valid: true
          })
        })
      }
    }
    fileReader.readAsBinaryString(file)
  },

  exportTemplate: () => {
    const $table = xTable.value
    exportData({
      table: $table,
      filename: i18n.global.t('router.sideBar.userManagement'),
      mode: 'header',
      columnFilterMethod({ column }: any) {
        return !['checkbox', 'seq'].includes(column?.type) && !['operate'].includes(column?.field)
      }
    })
  },

  deleteRow: (row: ImportVO) => {
    hookComponent.$dialog({
      content: i18n.global.t('system.tips.beforeDeleteDetailMessage'),
      handleConfirm: async () => {
        if (row) {
          const $table = xTable.value
          $table.remove(row)
        }
      }
    })
  }
})

watch(
  () => isShow.value,
  (val) => {
    if (val) {
      method.initForm()
    }
  }
)
</script>

<style scoped lang="less">
.v-form {
  div {
    margin-bottom: 7px;
  }
}
</style>

2.2 接口代码

代码语言:javascript
代码运行次数:0
复制
[Route("user")]
[ApiController]
[ApiExplorerSettings(GroupName = "Base")]
public class UserController : BaseController
{
    #region Args

    /// <summary>
    /// user Service
    /// </summary>
    private readonly IUserService _userService;

    /// <summary>
    /// Localizer Service
    /// </summary>
    private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
    #endregion

    #region constructor
    /// <summary>
    /// constructor
    /// </summary>
    /// <param name="userService">user Service</param>
    /// <param name="stringLocalizer">Localizer</param>
    public UserController(
         IUserService userService
       , IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
         )
    {
        this._userService = userService;
        this._stringLocalizer = stringLocalizer;
    }
    #endregion

    #region Api
    /// <summary>
    /// get select items
    /// </summary>
    /// <returns></returns>
    [HttpGet("select-item")]
    public async Task<ResultModel<List<FormSelectItem>>> GetSelectItemsAsnyc()
    {
        var datas = await _userService.GetSelectItemsAsnyc(CurrentUser);
        return ResultModel<List<FormSelectItem>>.Success(datas);
    }
    /// <summary>
    /// page search
    /// </summary>
    /// <param name="pageSearch">args</param>
    /// <returns></returns>
    [HttpPost("list")]
    public async Task<ResultModel<PageData<UserViewModel>>> PageAsync(PageSearch pageSearch)
    {
        var (data, totals) = await _userService.PageAsync(pageSearch, CurrentUser);

        return ResultModel<PageData<UserViewModel>>.Success(new PageData<UserViewModel>
        {
            Rows = data,
            Totals = totals
        });
    }

    /// <summary>
    /// Get all records
    /// </summary>
    /// <returns>args</returns>
    [HttpGet("all")]
    public async Task<ResultModel<List<UserViewModel>>> GetAllAsync()
    {
        var data = await _userService.GetAllAsync(CurrentUser);
        if (data.Any())
        {
            return ResultModel<List<UserViewModel>>.Success(data);
        }
        else
        {
            return ResultModel<List<UserViewModel>>.Success(new List<UserViewModel>());
        }
    }

    /// <summary>
    /// Get a record by id
    /// </summary>
    /// <returns>args</returns>
    [HttpGet]
    public async Task<ResultModel<UserViewModel>> GetAsync(int id)
    {
        var data = await _userService.GetAsync(id);
        if (data != null)
        {
            return ResultModel<UserViewModel>.Success(data);
        }
        else
        {
            return ResultModel<UserViewModel>.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(UserViewModel viewModel)
    {
        viewModel.creator = CurrentUser.user_name;
        var (id, msg) = await _userService.AddAsync(viewModel, CurrentUser);
        if (id > 0)
        {
            return ResultModel<int>.Success(id);
        }
        else
        {
            return ResultModel<int>.Error(msg);
        }
    }
    /// <summary>
    /// 注册功能实现
    /// </summary>
    /// <param name="viewModel">args</param>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("register")]
    public async Task<ResultModel<string>> Register(RegisterViewModel viewModel)
    {
        var (flag, msg) = await _userService.Register(viewModel);
        if (flag)
        {
            return ResultModel<string>.Success(msg);
        }
        else
        {
            return ResultModel<string>.Error(msg);
        }
    }
    /// <summary>
    /// import users by excel
    /// </summary>
    /// <param name="excel_datas">excel datas</param>
    /// <returns></returns>
    [HttpPost("excel")]
    public async Task<ResultModel<string>> ExcelAsync(List<UserExcelImportViewModel> excel_datas)
    {
        var (flag, msg) = await _userService.ExcelAsync(excel_datas, CurrentUser);
        if (flag)
        {
            return ResultModel<string>.Success(msg);
        }
        else
        {
            return ResultModel<string>.Error(msg);
        }
    }
    /// <summary>
    /// update a record
    /// </summary>
    /// <param name="viewModel">args</param>
    /// <returns></returns>
    [HttpPut]
    public async Task<ResultModel<bool>> UpdateAsync(UserViewModel viewModel)
    {
        var (flag, msg) = await _userService.UpdateAsync(viewModel, CurrentUser);
        if (flag)
        {
            return ResultModel<bool>.Success(flag);
        }
        else
        {
            return ResultModel<bool>.Error(msg, 400, flag);
        }
    }

    /// <summary>
    /// delete a record
    /// </summary>
    /// <param name="id">id</param>
    /// <returns></returns>
    [HttpDelete]
    public async Task<ResultModel<string>> DeleteAsync(int id)
    {
        var (flag, msg) = await _userService.DeleteAsync(id);
        if (flag)
        {
            return ResultModel<string>.Success(msg);
        }
        else
        {
            return ResultModel<string>.Error(msg);
        }
    }
    /// <summary>
    /// reset password
    /// </summary>
    /// <param name="viewModel">viewmodel</param>
    /// <returns></returns>
    [HttpPost("reset-pwd")]
    public async Task<ResultModel<string>> ResetPwd(BatchOperationViewModel viewModel)
    {
        var (flag, msg) = await _userService.ResetPwd(viewModel);
        if (flag)
        {
            return ResultModel<string>.Success(msg);
        }
        else
        {
            return ResultModel<string>.Error(msg);
        }
    }
    /// <summary>
    /// change password
    /// </summary>
    /// <param name="viewModel">viewmodel</param>
    /// <returns></returns>
    [HttpPost("change-pwd")]
    public async Task<ResultModel<string>> ChangePwd(UserChangePwdViewModel viewModel)
    {
        var (flag, msg) = await _userService.ChangePwd(viewModel);
        if (flag)
        {
            return ResultModel<string>.Success(msg);
        }
        else
        {
            return ResultModel<string>.Error(msg);
        }
    }
    #endregion

}

3.商品类别设置

3.1 页面代码

1、主页面代码

代码语言:javascript
代码运行次数:0
复制
<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="12" sm="4">
                    <v-text-field
                      v-model="data.searchForm.userName"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('login.userName')"
                      variant="solo"
                    >
                    </v-text-field>
                  </v-col>
                  <v-col cols="12" sm="4">
                    <v-text-field
                      v-model="data.searchForm.userName1"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('login.userName')"
                      variant="solo"
                    >
                    </v-text-field>
                  </v-col>
                  <v-col cols="12" sm="4">
                    <v-text-field
                      v-model="data.searchForm.userName2"
                      clearable
                      hide-details
                      density="comfortable"
                      class="searchInput ml-5 mt-1"
                      :label="$t('login.userName')"
                      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" :tree-config="data.tableTreeConfig" align="center">
              <template #empty>
                {{ i18n.global.t('system.page.noData') }}
              </template>
              <vxe-column type="seq" width="80"></vxe-column>
              <vxe-column field="category_name" align="left" :title="$t('base.commodityCategorySetting.category_name')" tree-node></vxe-column>
              <vxe-column field="creator" :title="$t('base.commodityCategorySetting.creator')"></vxe-column>
              <vxe-column field="create_time" :title="$t('base.commodityCategorySetting.create_time')"></vxe-column>
              <vxe-column :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>
          </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 } from 'vue'
import { computedCardHeight, computedTableHeight, errorColor } from '@/constant/style'
import tooltipBtn from '@/components/tooltip-btn.vue'
import { DataProps, CategoryVO } from '@/types/Base/CommodityCategorySetting'
import { getCategoryAll, deleteCategory } from '@/api/base/commodityCategorySetting'
import { hookComponent } from '@/components/system'
import addOrUpdateDialog from './add-or-update-category.vue'
import i18n from '@/languages/i18n'
import { exportData } from '@/utils/exportTable'

const xTable = ref()

const data: DataProps = reactive({
  // searchForm: {
  //   userName: '',
  //   userName1: '',
  //   userName2: ''
  // },
  tableData: [],
  tableTreeConfig: {
    transform: true,
    rowField: 'id',
    parentField: 'parent_id'
  },
  // Dialog info
  showDialog: false,
  dialogForm: {
    id: 0,
    category_name: ''
  }
})

const method = reactive({
  sureSearch: () => {
    // console.log(data.searchForm)
  },
  // Find Data by Pagination
  getCommodityCategorySetting: async () => {
    const { data: res } = await getCategoryAll()
    if (!res.isSuccess) {
      hookComponent.$message({
        type: 'error',
        content: res.errorMessage
      })
      return
    }
    data.tableData = res.data
    // nextTick(() => {
    //   xTable.value.setAllTreeExpand(true)
    // })
  },
  // Add user
  add: () => {
    data.dialogForm = {
      id: 0,
      category_name: ''
    }
    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.getCommodityCategorySetting()
  },
  editRow(row: CategoryVO) {
    data.dialogForm = JSON.parse(JSON.stringify(row))
    // If there is no parent, the parent will not be brought in_ id
    if (data.dialogForm.parent_id === 0) {
      delete data.dialogForm.parent_id
    }
    data.showDialog = true
  },
  deleteRow(row: CategoryVO) {
    hookComponent.$dialog({
      content: i18n.global.t('system.tips.beforeDeleteMessage'),
      handleConfirm: async () => {
        if (row.id) {
          const { data: res } = await deleteCategory(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.commodityCategorySetting'),
      columnFilterMethod({ column }: any) {
        return !['checkbox'].includes(column?.type)
      }
    })
  }
})

onMounted(async () => {
  await method.getCommodityCategorySetting()
})

const cardHeight = computed(() => computedCardHeight({ hasTab: false }))

const tableHeight = computed(() => computedTableHeight({ hasTab: false, hasPager: false }))
</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、窗体代码

代码语言:javascript
代码运行次数:0
复制
<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.commodityCategorySetting')}`"></v-toolbar>
        <v-card-text>
          <v-form ref="formRef">
            <v-text-field
              v-model="data.form.category_name"
              :label="$t('base.commodityCategorySetting.category_name')"
              :rules="data.rules.category_name"
              variant="outlined"
            ></v-text-field>
            <v-select
              v-model="data.form.parent_id"
              :items="data.combobox.parent"
              item-title="label"
              item-value="value"
              :rules="data.rules.parent_id"
              :label="$t('base.commodityCategorySetting.parent_name')"
              variant="outlined"
              clearable
            ></v-select>
          </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 { CategoryVO } from '@/types/Base/CommodityCategorySetting'
import i18n from '@/languages/i18n'
import { hookComponent } from '@/components/system/index'
import { addCategory, updateCategory, getCategoryAll } from '@/api/base/commodityCategorySetting'
import { StringLength } from '@/utils/dataVerification/formRule'

const formRef = ref()
const emit = defineEmits(['close', 'saveSuccess'])

const props = defineProps<{
  showDialog: boolean
  form: CategoryVO
}>()

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<CategoryVO>({
    id: 0,
    category_name: ''
  }),
  rules: {
    category_name: [
      (val: string) => !!val || `${ i18n.global.t('system.checkText.mustInput') }${ i18n.global.t('base.commodityCategorySetting.category_name') }!`,
      (val: string) => StringLength(val, 0, 32) === '' || StringLength(val, 0, 32)
    ],
    parent_id: [],
    is_valid: []
  },
  combobox: ref<{
    parent: {
      label: string
      value: number
    }[]
  }>({
    parent: []
  })
})

const method = reactive({
  // Get the options required by the drop-down box
  getCombobox: async () => {
    data.combobox.parent = []
    const { data: res } = await getCategoryAll()
    if (!res.isSuccess) {
      return
    }
    for (const item of res.data) {
      data.combobox.parent.push({
        label: item.category_name,
        value: item.id
      })
    }
  },
  closeDialog: () => {
    emit('close')
  },
  submit: async () => {
    const { valid } = await formRef.value.validate()
    if (valid) {
      const { data: res } = dialogTitle.value === 'add' ? await addCategory(data.form) : await updateCategory(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.getCombobox()
      data.form = props.form
    }
  }
)
</script>

<style scoped lang="less">
.v-form {
  div {
    margin-bottom: 7px;
  }
}
</style>

3.2 接口代码

代码语言:javascript
代码运行次数:0
复制
    [Route("category")]
    [ApiController]
    [ApiExplorerSettings(GroupName = "Base")]
    public class CategoryController : BaseController
    {
        #region Args

        /// <summary>
        /// category Service
        /// </summary>
        private readonly ICategoryService _categoryService;

        /// <summary>
        /// Localizer Service
        /// </summary>
        private readonly IStringLocalizer<ModernWMS.Core.MultiLanguage> _stringLocalizer;
        #endregion

        #region constructor
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="categoryService">category Service</param>
        /// <param name="stringLocalizer">Localizer</param>
        public CategoryController(
            ICategoryService categoryService
          , IStringLocalizer<ModernWMS.Core.MultiLanguage> stringLocalizer
            )
        {
            this._categoryService = categoryService;
            this._stringLocalizer = stringLocalizer;
        }
        #endregion

        #region Api
        /// <summary>
        /// get all records
        /// </summary>
        /// <returns>args</returns>
        [HttpGet("all")]
        public async Task<ResultModel<List<CategoryViewModel>>> GetAllAsync()
        {
            var data = await _categoryService.GetAllAsync(CurrentUser);
            if (data.Any())
            {
                return ResultModel<List<CategoryViewModel>>.Success(data);
            }
            else
            {
                return ResultModel<List<CategoryViewModel>>.Success(new List<CategoryViewModel>());
            }
        }

        /// <summary>
        /// get a record by id
        /// </summary>
        /// <returns>args</returns>
        [HttpGet]
        public async Task<ResultModel<CategoryViewModel>> GetAsync(int id)
        {
            var data = await _categoryService.GetAsync(id);
            if (data != null)
            {
                return ResultModel<CategoryViewModel>.Success(data);
            }
            else
            {
                return ResultModel<CategoryViewModel>.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(CategoryViewModel viewModel)
        {
            var (id, msg) = await _categoryService.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(CategoryViewModel viewModel)
        {
            var (flag, msg) = await _categoryService.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 _categoryService.DeleteAsync(id);
            if (flag)
            {
                return ResultModel<string>.Success(msg);
            }
            else
            {
                return ResultModel<string>.Error(msg);
            }
        }
        #endregion

    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-02-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 一、基础设置
    • 1.菜单设置
      • 1.1 页面代码
      • 1.2 接口代码
    • 2.用户管理
      • 2.1 页面代码
      • 2.2 接口代码
    • 3.商品类别设置
      • 3.1 页面代码
      • 3.2 接口代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档