|
@@ -0,0 +1,217 @@
|
|
|
|
+<template>
|
|
|
|
+ <div id="dataList" v-show="view === viewType.DATA">
|
|
|
|
+ <el-row style="margin:10px 5px" justify="space-between">
|
|
|
|
+ <el-col :span="4">
|
|
|
|
+ <search-bar :fields="getFields()" @query-search="querySearch"></search-bar>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="4">
|
|
|
|
+ <el-button type="success" plain @click="toAddPage">添加数据</el-button>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="4">
|
|
|
|
+ <el-button type="primary" plain @click="changeShowFields">显示字段</el-button>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="8">
|
|
|
|
+ <pages v-model:page="page" :limit="limit" :total="total" @page-search="pageSearch" />
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ <el-table :data="list" height="70vh" border stripe style="width: 100%" @row-contextmenu="rightClick"
|
|
|
|
+ @row-click="leftClick">
|
|
|
|
+ <el-table-column v-for="i in getFields()" :key="i.prop" :prop="i.prop" :label="i.label" align="center" />
|
|
|
|
+ </el-table>
|
|
|
|
+ </div>
|
|
|
|
+ <div v-if="view === viewType.EDIT">
|
|
|
|
+ <json-editor :value="rightClickTarget" :fields="getFields()" @to-back="viewBack" @to-save="editorSave" />
|
|
|
|
+ </div>
|
|
|
|
+ <div v-show="showRightMenu" ref="rightMenu" class="rightMenu">
|
|
|
|
+ <el-card class="box-card" body-style="padding:10px">
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col :span="24" v-for="i in opera" :key="i.label">
|
|
|
|
+ <el-button :type="i.type" text @click.prevent="rightMenuBtnClick(i.event)">{{ i.label }}</el-button>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ </el-card>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup lang="ts">
|
|
|
|
+import { head } from 'lodash'
|
|
|
|
+import { ref, defineProps, computed } from 'vue';
|
|
|
|
+import { useRoute } from 'vue-router'
|
|
|
|
+import { query, create, updateOne, deleteOne, collectionOptions } from '../../api/curd'
|
|
|
|
+import searchBar from './searchBar.vue'
|
|
|
|
+import pages from './pages.vue'
|
|
|
|
+import jsonEditor from './jsonEditor.vue'
|
|
|
|
+import { get } from 'lodash'
|
|
|
|
+const route = useRoute();
|
|
|
|
+const props = defineProps<{
|
|
|
|
+ collection: string
|
|
|
|
+ dbName: string
|
|
|
|
+}>();
|
|
|
|
+const key = computed(() => {
|
|
|
|
+ return route.query.key;
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+// #region 分页,查询,查询条件
|
|
|
|
+/**当前页数 */
|
|
|
|
+const page = ref(1);
|
|
|
|
+/**分页大小 */
|
|
|
|
+const limit = ref(100);
|
|
|
|
+/**数据列表 */
|
|
|
|
+const list = ref([]);
|
|
|
|
+/**根据条件查询的数据总数 */
|
|
|
|
+const total = ref(0)
|
|
|
|
+// 获取列头
|
|
|
|
+const getFields = () => {
|
|
|
|
+ const obj = head(list.value);
|
|
|
|
+ interface IField {
|
|
|
|
+ prop: string
|
|
|
|
+ label: string
|
|
|
|
+ }
|
|
|
|
+ const fields: Array<IField> = [];
|
|
|
|
+ for (const key in obj) {
|
|
|
|
+ fields.push({ prop: key, label: key })
|
|
|
|
+ }
|
|
|
|
+ if (fields.length > 0) {
|
|
|
|
+ const i = fields.findIndex(f => f.prop === '_id')
|
|
|
|
+ if (i > -1) {
|
|
|
|
+ const r = fields.find(f => f.prop === '_id')
|
|
|
|
+ fields.splice(i, 1)
|
|
|
|
+ fields.unshift(r)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return fields
|
|
|
|
+}
|
|
|
|
+/**查询数据必备的数据 */
|
|
|
|
+const defaultQuery = computed(() => {
|
|
|
|
+ const obj: collectionOptions = { key: key.value as string, db: props.dbName, collection: props.collection }
|
|
|
|
+ return obj;
|
|
|
|
+})
|
|
|
|
+/**查询条件 */
|
|
|
|
+const queryObject = ref({});
|
|
|
|
+/**查询的执行函数 */
|
|
|
|
+const toSearch = async (s = 0, l = limit.value) => {
|
|
|
|
+ const qo = { skip: s, limit: l, ...defaultQuery.value, ...queryObject.value };
|
|
|
|
+ const res = await query({ query: qo })
|
|
|
|
+ list.value = get(res, 'data', []);
|
|
|
|
+ total.value = get(res, 'total', 0);
|
|
|
|
+}
|
|
|
|
+/**默认初始化查 */
|
|
|
|
+toSearch();
|
|
|
|
+/**因条件修改查询 */
|
|
|
|
+const querySearch = (q) => {
|
|
|
|
+ queryObject.value = q;
|
|
|
|
+ page.value = 1;
|
|
|
|
+ toSearch()
|
|
|
|
+}
|
|
|
|
+/**因分页修改查询 */
|
|
|
|
+const pageSearch = (skip: number) => {
|
|
|
|
+ toSearch(skip)
|
|
|
|
+}
|
|
|
|
+// #endregion
|
|
|
|
+
|
|
|
|
+const changeShowFields = () => {
|
|
|
|
+ ElMessage.error('没做呢!赶紧滴!')
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**视图类型 */
|
|
|
|
+enum viewType {
|
|
|
|
+ DATA,
|
|
|
|
+ EDIT
|
|
|
|
+};
|
|
|
|
+/**右键菜单 */
|
|
|
|
+const opera = [
|
|
|
|
+ {
|
|
|
|
+ label: '修改',
|
|
|
|
+ type: 'primary',
|
|
|
|
+ event: 'rightMenuToUpdate'
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ label: '删除',
|
|
|
|
+ type: 'danger',
|
|
|
|
+ event: 'rightMenuToDelete'
|
|
|
|
+ }
|
|
|
|
+]
|
|
|
|
+/**是否显示右键菜单 */
|
|
|
|
+const showRightMenu = ref(false);
|
|
|
|
+/**当前视图变量 */
|
|
|
|
+const view = ref(viewType.DATA)
|
|
|
|
+/**去添加数据,进入编辑页面 */
|
|
|
|
+const toAddPage = () => {
|
|
|
|
+ view.value = viewType.EDIT
|
|
|
|
+}
|
|
|
|
+/**json编辑器返回 */
|
|
|
|
+const viewBack = () => {
|
|
|
|
+ view.value = viewType.DATA
|
|
|
|
+}
|
|
|
|
+/**json编辑器保存 */
|
|
|
|
+const editorSave = async (data: object) => {
|
|
|
|
+ let result;
|
|
|
|
+ if ('_id' in data) {
|
|
|
|
+ // update
|
|
|
|
+ result = await updateOne(data, defaultQuery.value)
|
|
|
|
+ } else {
|
|
|
|
+ // create
|
|
|
|
+ result = await create(data, defaultQuery.value)
|
|
|
|
+ }
|
|
|
|
+ if (result) {
|
|
|
|
+ ElMessage.success('操作成功')
|
|
|
|
+ viewBack();
|
|
|
|
+ toSearch();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+/**右键菜单的实例 */
|
|
|
|
+const rightMenu = ref()
|
|
|
|
+/**右键菜单的数据 */
|
|
|
|
+const rightClickTarget = ref()
|
|
|
|
+/**表格右键事件-召唤菜单框 */
|
|
|
|
+const rightClick = (row: object, column: object, e: any) => {
|
|
|
|
+ let menu = rightMenu.value as HTMLElement;
|
|
|
|
+ let x = e.clientX;
|
|
|
|
+ let y = e.clientY;
|
|
|
|
+ menu.style.top = `${y}px`
|
|
|
|
+ menu.style.left = `${x}px`;
|
|
|
|
+ showRightMenu.value = true;
|
|
|
|
+ rightClickTarget.value = row;
|
|
|
|
+}
|
|
|
|
+/**右键菜单统一事件 */
|
|
|
|
+const rightMenuBtnClick = (method) => {
|
|
|
|
+ const fobj = { rightMenuToUpdate, rightMenuToDelete }
|
|
|
|
+ fobj[method]()
|
|
|
|
+}
|
|
|
|
+/**表格右键事件-修改 */
|
|
|
|
+const rightMenuToUpdate = () => {
|
|
|
|
+ view.value = viewType.EDIT
|
|
|
|
+ leftClick();
|
|
|
|
+}
|
|
|
|
+/**表格右键事件-删除 */
|
|
|
|
+const rightMenuToDelete = () => {
|
|
|
|
+ leftClick();
|
|
|
|
+ ElMessageBox.confirm('确认删除数据?', '删除提示', {
|
|
|
|
+ confirmButtonText: '删除',
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
+ type: 'warning',
|
|
|
|
+ }).then(async () => {
|
|
|
|
+ // 删除
|
|
|
|
+ const result = await deleteOne(rightClickTarget.value, defaultQuery.value)
|
|
|
|
+ if (result) {
|
|
|
|
+ ElMessage.success('操作成功');
|
|
|
|
+ toSearch()
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+/**表格左键-关闭右键菜单 */
|
|
|
|
+const leftClick = () => {
|
|
|
|
+ showRightMenu.value = false
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style scoped>
|
|
|
|
+.box-card {
|
|
|
|
+ width: 80px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.rightMenu {
|
|
|
|
+ position: fixed;
|
|
|
|
+ z-index: 9999
|
|
|
|
+}
|
|
|
|
+</style>
|