Prechádzať zdrojové kódy

Merge branch 'main' of http://git.cc-lotus.info/util/web-template-vue3-js

lrf 1 rok pred
rodič
commit
64bd0a1f1e

+ 1 - 1
src/components/custom/custom-form.vue

@@ -121,7 +121,7 @@ const { t } = useI18n()
 const submitTextDefault = t('common.save')
 const props = defineProps({
   modelValue: { type: Object },
-  rules: { type: Array, default: () => [] },
+  rules: { type: Array, default: () => {} },
   labelWidth: { type: String, default: 'auto' },
   disabled: { type: Boolean, default: false },
   fields: { type: Array, default: () => [] },

+ 4 - 0
src/components/custom/custom-search-bar.vue

@@ -95,6 +95,7 @@
       </el-form-item>
       <el-form-item v-if="fields.length > 0">
         <el-button type="primary" @click="toClick">{{ $t('common.search') }}</el-button>
+        <el-button type="default" @click="toReset">{{ $t('common.reset') }}</el-button>
       </el-form-item>
     </el-form>
   </div>
@@ -120,6 +121,9 @@ const form = computed({
 const toClick = () => {
   emits('search')
 }
+const toReset = () => {
+  emits('reset')
+}
 const getField = (item, data) => {
   let res = get(data, item, null)
   if (item === 'type') res = res === null ? `text` : res

+ 2 - 0
src/lang/package/zh-cn/common.js

@@ -3,8 +3,10 @@ export default {
   add: '添加',
   update: '修改',
   delete: '删除',
+  dict: '字典数据',
   delete_confirm: '您确定删除该数据?',
   search: '查询',
+  reset: '重置',
   view: '查看',
   save: '保存',
   submit: '提交',

+ 20 - 0
src/lang/package/zh-cn/pages.js

@@ -51,5 +51,25 @@ export default {
     changeToAbled: '您确定要启用该用户?',
     changeToDisabled: '您确定要禁用该用户?',
     password: '密码'
+  },
+  dict: {
+    addDialogTitle: '新增字典类型',
+    upDialogTitle: '修改字典类型',
+    title: '字典名称',
+    code: '编码',
+    is_use: '是否启用',
+    remark: '备注',
+    titleMessage: '请输入字典名称',
+    codeMessage: '请输入编码'
+  },
+  dictData: {
+    dialogTitle: '管理字典数据',
+    codeDialogTitle: '字典数据',
+    label: '数据显示值',
+    value: '数据选择值',
+    sort: '排序',
+    is_use: '是否启用',
+    labelMessage: '请输入数据显示值',
+    valueMessage: '请输入数据选择值'
   }
 }

+ 1 - 1
src/store/api/system/dictType.js

@@ -4,7 +4,7 @@ import { get } from 'lodash-es'
 const url = '/dictType'
 const axios = new AxiosWrapper()
 
-export const DictType = defineStore('dictType', () => {
+export const DictTypeStore = defineStore('dictType', () => {
   const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
     let cond = {}
     if (skip) cond.skip = skip

+ 110 - 40
src/views/system/dict/index.vue

@@ -1,61 +1,131 @@
 <template>
   <div class="main animate__animated animate__backInRight" v-loading="loading">
-    <custom-search-bar :fields="fields.filter((f) => f.filter)" v-model="searchForm">
-      <template #test3>
-        <el-option label="s3" value="s3"></el-option>
-      </template>
-      <template #test4>
-        <el-radio label="s4">s4</el-radio>
-        <el-radio label="s42">s42</el-radio>
-        <el-radio label="s43">s43</el-radio>
-        <el-radio label="s44">s44</el-radio>
-        <el-radio label="s45">s45</el-radio>
-      </template>
-    </custom-search-bar>
-    <!-- <custom-button-bar :fields="buttonFields"></custom-button-bar> -->
-    <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @edit="toEdit"></custom-table>
-    <!-- <custom-form v-model="data" :fields="fields" @save="toSave"></custom-form> -->
+    <custom-search-bar :fields="fields.filter((f) => f.isSearch)" v-model="searchForm" @search="search" @reset="toReset"></custom-search-bar>
+    <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
+    <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @dict="toDict" @edit="toEdit" @delete="toDelete"></custom-table>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose" :top="dialog.top">
+      <el-row>
+        <el-col :span="24" v-if="dialog.type == '1'">
+          <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave">
+            <template #is_use>
+              <el-radio v-for="i in isUseList" :key="i._id" :label="i.value">{{ i.label }}</el-radio>
+            </template>
+          </custom-form>
+        </el-col>
+        <el-col :span="24" v-if="dialog.type == '2'">
+          <dictData></dictData>
+        </el-col>
+      </el-row>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
+import dictData from '@/views/system/dictData/index.vue'
+const $checkRes = inject('$checkRes')
+import { cloneDeep, get } from 'lodash-es'
+const { t } = useI18n()
+// 接口
+import { DictTypeStore } from '@/store/api/system/dictType'
+import { DictDataStore } from '@/store/api/system/dictData'
+const store = DictTypeStore()
+const dictDataStore = DictDataStore()
 const data = ref([])
 const searchForm = ref({})
 const fields = [
-  { label: '测试', model: 'test', filter: true },
-  { label: '测试2', model: 'test2', filter: true },
-  { label: '测试3', model: 'test3', filter: true, type: 'select' },
-  { label: '测试4', model: 'test4', filter: true, type: 'radio' },
-  { label: '测试5', model: 'test5', filter: true, type: 'datetime' },
-  { label: '测试6', model: 'test6', filter: true, type: 'inputnumber' },
-  { label: '测试7', model: 'test7', filter: true },
-  { label: '测试8', model: 'test8', filter: true },
-  { label: '测试9', model: 'test9', filter: true },
-  { label: '测试10', model: 'test10', filter: true }
+  { label: t('pages.dict.title'), model: 'title', isSearch: true },
+  { label: t('pages.dict.code'), model: 'code', isSearch: true },
+  { label: t('pages.dict.is_use'), model: 'is_use', format: (i) => getDict(i) },
+  { label: t('pages.dict.remark'), model: 'remark' }
 ]
-const opera = [{ label: '修改', method: 'edit', confirm: true }]
-const buttonFields = [
-  { label: '添加', method: 'pages.system.system_menus.add' },
-  { label: '导出', method: 'pages.system.system_menus.export', type: 'success' }
+const opera = [
+  { label: t('common.dict'), method: 'dict' },
+  { label: t('common.update'), method: 'edit' },
+  { label: t('common.delete'), method: 'delete', confirm: true, type: 'danger' }
 ]
+const buttonFields = [{ label: t('common.add'), method: 'add' }]
+let skip = 0
+let limit = inject('limit')
 const total = ref(20)
-
-const toSave = (val) => {
-  console.log(val)
-  console.log(data)
-}
-const search = (query) => {
-  console.log(query)
-}
-const toEdit = (data) => {
-  console.log(data)
-}
+const isUseList = ref([])
 // 加载中
 const loading = ref(false)
+const formFields = [
+  { label: t('pages.dict.title'), model: 'title' },
+  { label: t('pages.dict.code'), model: 'code' },
+  { label: t('pages.dict.is_use'), model: 'is_use', type: 'radio' },
+  { label: t('pages.dict.remark'), model: 'remark', type: 'textarea' }
+]
+const rules = reactive({ title: [{ required: true, message: t('pages.dict.titleMessage'), trigger: 'blur' }], code: [{ required: true, message: t('pages.dict.codeMessage'), trigger: 'blur' }] })
+const dialog = ref({ type: '1', show: false, title: t('pages.dict.dialogTitle'), top: '15vh' })
+const form = ref({})
 // 请求
 onMounted(async () => {
   loading.value = true
+  await searchOther()
+  await search({ skip, limit })
   loading.value = false
 })
+
+const searchOther = async () => {
+  const result = await dictDataStore.query({ code: 'isUse', is_use: '0' })
+  if ($checkRes(result)) isUseList.value = result.data
+}
+const search = async (query = { skip: 0, limit }) => {
+  const info = { skip: query.skip, limit: query.limit, ...searchForm.value }
+  const res = await store.query(info)
+  if (res.errcode == '0') {
+    data.value = res.data
+    total.value = res.total
+  }
+}
+// 字典数据转换
+const getDict = (data) => {
+  const res = isUseList.value.find((f) => f.value == data)
+  return get(res, 'label')
+}
+// 添加
+const toAdd = () => {
+  dialog.value = { type: '1', show: true, title: t('pages.dict.addDialogTitle'), top: '15vh' }
+}
+// 字典数据
+const toDict = (data) => {
+  form.value = data
+  dialog.value = { type: '2', show: true, title: `【${data.title}】 ` + t('pages.dictData.codeDialogTitle'), top: '5vh' }
+}
+// 修改
+const toEdit = (data) => {
+  form.value = data
+  dialog.value = { type: '1', show: true, title: t('pages.dict.upDialogTitle'), top: '15vh' }
+}
+// 删除
+const toDelete = async (data) => {
+  const res = await store.del(data._id)
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+  }
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  let res
+  if (get(data, '_id')) res = await store.update(data)
+  else res = await store.create(data)
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+    toClose()
+  }
+}
+// 重置
+const toReset = async () => {
+  searchForm.value = {}
+  await search({ skip, limit })
+}
+const toClose = () => {
+  form.value = {}
+  dialog.value = { show: false }
+}
+// provide
+provide('isUseList', isUseList)
+provide('codeInfo', form)
 </script>
 <style scoped lang="scss"></style>

+ 96 - 6
src/views/system/dictData/index.vue

@@ -1,20 +1,110 @@
 <template>
-  <div id="index">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <el-col :span="24" class="one"> 字典数据 </el-col>
-      </el-col>
-    </el-row>
+  <div class="main animate__animated animate__backInRight" v-loading="loading">
+    <custom-search-bar :fields="fields.filter((f) => f.isSearch)" v-model="searchForm" @search="search" @reset="toReset"></custom-search-bar>
+    <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
+    <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @edit="toEdit" @delete="toDelete"></custom-table>
+    <el-dialog v-model="dialog" :title="$t('pages.dictData.dialogTitle')" :destroy-on-close="false" @close="toClose" width="30%">
+      <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave">
+        <template #is_use>
+          <el-radio v-for="i in isUseList" :key="i._id" :label="i.value">{{ i.label }}</el-radio>
+        </template>
+      </custom-form>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
+const $checkRes = inject('$checkRes')
+import { cloneDeep, get } from 'lodash-es'
+const { t } = useI18n()
+// 接口
+import { DictDataStore } from '@/store/api/system/dictData'
+const store = DictDataStore()
+const data = ref([])
+const searchForm = ref({})
+const fields = [
+  { label: t('pages.dictData.label'), model: 'label', isSearch: true },
+  { label: t('pages.dictData.value'), model: 'value' },
+  { label: t('pages.dictData.sort'), model: 'sort' },
+  { label: t('pages.dictData.is_use'), model: 'is_use', format: (i) => getDict(i) }
+]
+const opera = [
+  { label: t('common.update'), method: 'edit' },
+  { label: t('common.delete'), method: 'delete', confirm: true, type: 'danger' }
+]
+const buttonFields = [{ label: t('common.add'), method: 'add' }]
+let skip = 0
+let limit = inject('limit')
+const total = ref(20)
+const isUseList = inject('isUseList')
+const codeInfo = inject('codeInfo')
 // 加载中
 const loading = ref(false)
+const formFields = [
+  { label: t('pages.dictData.label'), model: 'label' },
+  { label: t('pages.dictData.value'), model: 'value' },
+  { label: t('pages.dictData.sort'), model: 'sort', type: 'number' },
+  { label: t('pages.dictData.is_use'), model: 'is_use', type: 'radio' }
+]
+const rules = reactive({
+  label: [{ required: true, message: t('pages.dictData.labelMessage'), trigger: 'blur' }],
+  value: [{ required: true, message: t('pages.dictData.valueMessage'), trigger: 'blur' }]
+})
+const dialog = ref(false)
+const form = ref({})
 // 请求
 onMounted(async () => {
   loading.value = true
+  await search({ skip, limit })
   loading.value = false
 })
+const search = async (query = { skip: 0, limit }) => {
+  const info = { skip: query.skip, limit: query.limit, ...searchForm.value, code: codeInfo.value.code }
+  const res = await store.query(info)
+  if (res.errcode == '0') {
+    data.value = res.data
+    total.value = res.total
+  }
+}
+// 字典数据转换
+const getDict = (data) => {
+  const res = isUseList.value.find((f) => f.value == data)
+  return get(res, 'label')
+}
+// 添加
+const toAdd = () => {
+  dialog.value = true
+}
+// 修改
+const toEdit = (data) => {
+  form.value = data
+  dialog.value = true
+}
+// 删除
+const toDelete = async (data) => {
+  const res = await store.del(data._id)
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+  }
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  let res
+  if (get(data, '_id')) res = await store.update(data)
+  else res = await store.create({ ...data, code: codeInfo.value.code })
+  if ($checkRes(res, true)) {
+    search({ skip: 0, limit })
+    toClose()
+  }
+}
+// 重置
+const toReset = async () => {
+  searchForm.value = {}
+  await search({ skip, limit })
+}
+const toClose = () => {
+  form.value = {}
+  dialog.value = false
+}
 </script>
 <style scoped lang="scss"></style>

+ 2 - 9
src/views/system/role/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="main animate__animated animate__backInRight" v-loading="loading">
-    <el-row style="height: 5vh; padding: 5px">
+    <el-row style="padding: 5px">
       <el-col :span="24" style="text-align: right">
         <el-button type="primary" @click="toAdd" v-method="'add'">{{ $t('common.add') }}</el-button>
       </el-col>
@@ -11,14 +11,7 @@
       </el-col>
     </el-row>
     <el-row justify="end" style="margin-top: 10px; height: 5vh">
-      <el-pagination
-        background
-        layout="total, prev, pager, next"
-        :page-size="limit"
-        :total="total"
-        v-model:current-page="currentPage"
-        @current-change="changePage"
-      />
+      <el-pagination background layout="total, prev, pager, next" :page-size="limit" :total="total" v-model:current-page="currentPage" @current-change="changePage" />
     </el-row>
     <el-dialog v-model="dialog" :title="$t('pages.role.dialogTitle')" :destroy-on-close="true" @close="toClose">
       <role-form></role-form>

+ 6 - 1
src/views/user/admin/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="main animate__animated animate__backInRight">
-    <custom-search-bar v-model="searchForm" :fields="fields.filter((f) => f.filter)" @search="search"></custom-search-bar>
+    <custom-search-bar v-model="searchForm" :fields="fields.filter((f) => f.filter)" @search="search" @reset="toReset"></custom-search-bar>
     <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
     <custom-table :data="data" :fields="fields" @search="search" :total="total" :opera="opera" @edit="toEdit" @changeUse="toChangeUse" @delete="toDelete" @rp="toResetPwd"></custom-table>
     <el-dialog v-model="dialog" :title="$t('pages.menus.dialogTitle')" :destroy-on-close="false" @close="toClose">
@@ -167,5 +167,10 @@ const toClose = () => {
   form.value = {}
   dialog.value = false
 }
+// 重置
+const toReset = async () => {
+  searchForm.value = {}
+  await search({ skip, limit })
+}
 </script>
 <style scoped></style>