Ver código fonte

refactor(仓库管理): 替换请求方式以获取仓库选项

- 将仓库选项的获取方式从直接请求API改为使用新的API接口`getRepositoryOptions`,简化了代码逻辑。
- 移除了不必要的状态检查和数据映射,优化了`loadWarehouseOptions`函数的实现。
ylong 1 mês atrás
pai
commit
e2b4073504

+ 55 - 0
src/api/activation/repository.js

@@ -0,0 +1,55 @@
+import request from '@/utils/request';
+
+function isSuccess(code) {
+    return code === 200 || code === 0;
+}
+
+function unwrapList(res) {
+    const body = res?.data || {};
+    if (!isSuccess(body.code)) {
+        return Promise.reject(new Error(body.msg || '请求失败'));
+    }
+    return body.data || body.rows || [];
+}
+
+/** 已配置仓库数据权限的管理员列表(不分页) */
+export function listRepositoryRole() {
+    return request
+        .get('/activation/bookActivationCodeRepository/listRepositoryRole')
+        .then(unwrapList);
+}
+
+/** 当前账号有权限的仓库(下拉选择用,admin 返回全部) */
+export function getAllRepositories() {
+    return request
+        .get('/activation/bookActivationCodeRepository/getAll')
+        .then(unwrapList);
+}
+
+/** 仓库下拉选项,默认只返回启用仓库 */
+export function getRepositoryOptions({ enabledOnly = true } = {}) {
+    return getAllRepositories().then((list) =>
+        list
+            .filter((item) => {
+                if (!enabledOnly) return true;
+                return item.status == null || item.status == 1;
+            })
+            .map((item) => ({
+                label: item.repositoryName,
+                value: item.id
+            }))
+    );
+}
+
+/** 新增/编辑管理员仓库数据权限 */
+export function updateRepositoryRole(data) {
+    return request.post(
+        '/activation/bookActivationCodeRepository/updateRepositoryRole',
+        data
+    );
+}
+
+/** 状态正常的管理员(下拉选择用,出参 userId / nickName) */
+export function listAdmins() {
+    return request.get('/system/user/listNormalAdmins').then(unwrapList);
+}

+ 6 - 16
src/views/code/list/components/code-search.vue

@@ -13,7 +13,7 @@
 <script setup>
     import { reactive, ref, computed, defineEmits, onMounted } from 'vue';
     import ProSearch from '@/components/CommonPage/ProSearch2.vue';
-    import request from '@/utils/request';
+    import { getRepositoryOptions } from '@/api/activation/repository';
 
     const emit = defineEmits(['search']);
 
@@ -41,22 +41,12 @@
     });
 
     function loadWarehouseOptions() {
-        request
-            .get('/activation/bookActivationCodeRepository/pagelist', {
-                params: {
-                    status: '1',
-                    pageNum: 1,
-                    pageSize: 500
-                }
+        getRepositoryOptions()
+            .then((list) => {
+                warehouseOptions.value = list;
             })
-            .then((res) => {
-                if (res.data.code === 200) {
-                    const list = res.data.rows || res.data.data || [];
-                    warehouseOptions.value = list.map((item) => ({
-                        label: item.repositoryName,
-                        value: item.id
-                    }));
-                }
+            .catch(() => {
+                warehouseOptions.value = [];
             });
     }
 

+ 6 - 16
src/views/code/record/page-search.vue

@@ -13,7 +13,7 @@
 <script setup>
     import { reactive, ref, computed, defineEmits, onMounted } from 'vue';
     import ProSearch from '@/components/CommonPage/ProSearch2.vue';
-    import request from '@/utils/request';
+    import { getRepositoryOptions } from '@/api/activation/repository';
 
     const emit = defineEmits(['search']);
 
@@ -128,22 +128,12 @@
     });
 
     function loadWarehouseOptions() {
-        request
-            .get('/activation/bookActivationCodeRepository/pagelist', {
-                params: {
-                    status: '1',
-                    pageNum: 1,
-                    pageSize: 500
-                }
+        getRepositoryOptions()
+            .then((list) => {
+                warehouseOptions.value = list;
             })
-            .then((res) => {
-                if (res.data.code === 200) {
-                    const list = res.data.rows || res.data.data || [];
-                    warehouseOptions.value = list.map((item) => ({
-                        label: item.repositoryName,
-                        value: item.id
-                    }));
-                }
+            .catch(() => {
+                warehouseOptions.value = [];
             });
     }
 

+ 34 - 0
src/views/code/repositoryRole/components/page-search.vue

@@ -0,0 +1,34 @@
+<!-- 搜索表单 -->
+<template>
+    <ele-card :body-style="{ paddingBottom: '8px' }">
+        <ProSearch
+            :items="formItems"
+            ref="searchRef"
+            @search="search"
+            :initKeys="initKeys"
+        />
+    </ele-card>
+</template>
+
+<script setup>
+    import { reactive, ref } from 'vue';
+    import ProSearch from '@/components/CommonPage/ProSearch2.vue';
+
+    const emit = defineEmits(['search']);
+
+    const formItems = reactive([
+        { type: 'input', label: '管理员', prop: 'keyword' },
+        { type: 'input', label: '仓库名称', prop: 'repositoryName' }
+    ]);
+
+    const initKeys = reactive({
+        keyword: '',
+        repositoryName: ''
+    });
+
+    const searchRef = ref(null);
+
+    const search = (data) => {
+        emit('search', { ...data });
+    };
+</script>

+ 127 - 0
src/views/code/repositoryRole/components/role-edit.vue

@@ -0,0 +1,127 @@
+<template>
+    <simple-form-modal
+        :title="title"
+        :items="formItems"
+        ref="editRef"
+        :baseUrl="baseUrl"
+        idKey="userId"
+        labelWidth="120px"
+        width="560px"
+        :formatData="formatData"
+        @success="(data) => emit('success', data)"
+    />
+</template>
+
+<script setup>
+    import { reactive, ref, computed } from 'vue';
+    import SimpleFormModal from '@/components/CommonPage/SimpleFormModal.vue';
+    import {
+        getAllRepositories,
+        listAdmins
+    } from '@/api/activation/repository';
+
+    const emit = defineEmits(['success']);
+
+    const title = ref('新增仓库权限');
+    const isEdit = ref(false);
+    const editRef = ref(null);
+    const adminOptions = ref([]);
+    const repositoryOptions = ref([]);
+
+    const formItems = computed(() => [
+        {
+            type: 'select',
+            label: '管理员',
+            prop: 'userId',
+            required: true,
+            options: adminOptions.value,
+            props: {
+                filterable: true,
+                disabled: isEdit.value
+            }
+        },
+        {
+            type: 'select',
+            label: '仓库权限',
+            prop: 'repositoryIds',
+            required: true,
+            options: repositoryOptions.value,
+            props: {
+                multiple: true,
+                filterable: true
+            }
+        }
+    ]);
+
+    const baseUrl = reactive({
+        add: '/activation/bookActivationCodeRepository/updateRepositoryRole',
+        update: '/activation/bookActivationCodeRepository/updateRepositoryRole'
+    });
+
+    function formatAdminLabel(item) {
+        return item.nickName || String(item.userId);
+    }
+
+    function formatData(data) {
+        return {
+            userId: data.userId,
+            repositoryIds: data.repositoryIds || []
+        };
+    }
+
+    async function loadRepositories() {
+        try {
+            const list = await getAllRepositories();
+            repositoryOptions.value = list.map((item) => ({
+                label: item.repositoryName,
+                value: item.id
+            }));
+        } catch (e) {
+            repositoryOptions.value = [];
+        }
+    }
+
+    async function loadAdmins(excludeUserIds = []) {
+        try {
+            const excludeSet = new Set(excludeUserIds.map(String));
+            const list = await listAdmins();
+            adminOptions.value = list
+                .filter((item) => !excludeSet.has(String(item.userId)))
+                .map((item) => ({
+                    label: formatAdminLabel(item),
+                    value: item.userId
+                }));
+        } catch (e) {
+            adminOptions.value = [];
+        }
+    }
+
+    async function handleOpen(row, assignedUserIds = []) {
+        isEdit.value = !!(row && row.userId);
+        title.value = isEdit.value ? '编辑仓库权限' : '新增仓库权限';
+
+        await loadRepositories();
+
+        if (isEdit.value) {
+            adminOptions.value = [
+                {
+                    label: formatAdminLabel(row),
+                    value: row.userId
+                }
+            ];
+            editRef.value?.handleOpen({
+                userId: row.userId,
+                repositoryIds: (row.repositories || []).map((item) => item.id)
+            });
+            return;
+        }
+
+        await loadAdmins(assignedUserIds);
+        editRef.value?.handleOpen({
+            userId: undefined,
+            repositoryIds: []
+        });
+    }
+
+    defineExpose({ handleOpen });
+</script>

+ 167 - 0
src/views/code/repositoryRole/index.vue

@@ -0,0 +1,167 @@
+<template>
+    <ele-page flex-table>
+        <page-search @search="reload" />
+
+        <common-table
+            ref="pageRef"
+            :pageConfig="pageConfig"
+            :columns="columns"
+            :datasource="datasource"
+            :pagination="false"
+        >
+            <template #toolbar>
+                <el-button
+                    type="primary"
+                    plain
+                    :icon="PlusOutlined"
+                    v-permission="'activation:bookActivationCodeRepository:updateRole'"
+                    @click="handleUpdate()"
+                >
+                    新增
+                </el-button>
+            </template>
+
+            <template #repositories="{ row }">
+                <div v-if="row.repositories?.length" class="repo-tags">
+                    <el-tag
+                        v-for="item in row.repositories"
+                        :key="item.id"
+                        size="small"
+                        class="repo-tag"
+                    >
+                        {{ item.repositoryName }}
+                    </el-tag>
+                </div>
+                <span v-else>-</span>
+            </template>
+
+            <template #action="{ row }">
+                <el-button
+                    type="primary"
+                    link
+                    v-permission="'activation:bookActivationCodeRepository:updateRole'"
+                    @click="handleUpdate(row)"
+                >
+                    编辑
+                </el-button>
+            </template>
+        </common-table>
+
+        <role-edit ref="editRef" @success="reload()" />
+    </ele-page>
+</template>
+
+<script setup>
+    import { ref, reactive } from 'vue';
+    import { PlusOutlined } from '@/components/icons';
+    import CommonTable from '@/components/CommonPage/CommonTable.vue';
+    import pageSearch from './components/page-search.vue';
+    import roleEdit from './components/role-edit.vue';
+    import { listRepositoryRole } from '@/api/activation/repository';
+
+    defineOptions({ name: 'CodeRepositoryRole' });
+
+    const pageRef = ref(null);
+    const editRef = ref(null);
+    const roleList = ref([]);
+
+    const pageConfig = reactive({
+        fileName: '管理员仓库权限',
+        cacheKey: 'codeRepositoryRoleTable',
+        rowKey: 'userId'
+    });
+
+    const columns = ref([
+        {
+            label: '管理员',
+            prop: 'nickName',
+            align: 'center',
+            minWidth: 120,
+            formatter: (row) => row.nickName || '-'
+        },
+        {
+            label: '账号',
+            prop: 'userName',
+            align: 'center',
+            minWidth: 120,
+            formatter: (row) => row.userName || '-'
+        },
+        {
+            label: '仓库权限',
+            prop: 'repositories',
+            align: 'left',
+            minWidth: 280,
+            slot: 'repositories'
+        },
+        {
+            label: '操作人',
+            prop: 'operatorNickName',
+            align: 'center',
+            minWidth: 120,
+            formatter: (row) => row.operatorNickName || '-'
+        },
+        {
+            label: '操作时间',
+            prop: 'operatorTime',
+            align: 'center',
+            minWidth: 170,
+            formatter: (row) => row.operatorTime || row.updateTime || '-'
+        },
+        {
+            columnKey: 'action',
+            label: '操作',
+            width: 120,
+            align: 'center',
+            slot: 'action'
+        }
+    ]);
+
+    function matchKeyword(row, keyword) {
+        if (!keyword) return true;
+        const text = `${row.nickName || ''} ${row.userName || ''}`.toLowerCase();
+        return text.includes(keyword.toLowerCase());
+    }
+
+    function matchRepository(row, repositoryName) {
+        if (!repositoryName) return true;
+        return (row.repositories || []).some((item) =>
+            (item.repositoryName || '')
+                .toLowerCase()
+                .includes(repositoryName.toLowerCase())
+        );
+    }
+
+    const datasource = ({ where }) => {
+        return listRepositoryRole().then((list) => {
+            roleList.value = list;
+            const keyword = (where?.keyword || '').trim();
+            const repositoryName = (where?.repositoryName || '').trim();
+            return list.filter(
+                (row) =>
+                    matchKeyword(row, keyword) &&
+                    matchRepository(row, repositoryName)
+            );
+        });
+    };
+
+    function reload(where) {
+        pageRef.value?.reload(where);
+    }
+
+    function handleUpdate(row) {
+        const assignedUserIds = roleList.value.map((item) => item.userId);
+        editRef.value?.handleOpen(row, assignedUserIds);
+    }
+</script>
+
+<style scoped>
+    .repo-tags {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 6px;
+    }
+
+    .repo-tag {
+        margin: 0;
+    }
+</style>