Commit bb414f3a by qinjianhui

feat: 外部授权

parent f13a0f82
......@@ -13,12 +13,17 @@ declare module 'vue' {
DateRangePicker: typeof import('./src/components/Form.vue/DateRangePicker.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
......@@ -27,6 +32,8 @@ declare module 'vue' {
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
......@@ -34,6 +41,7 @@ declare module 'vue' {
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
......
import { BasePaginationData, BaseRespData } from '@/types/api'
import axios from './axios'
import { ExternalAuthListData } from '@/types/api/externalAuth'
export function getExternalAuthorisationListApi(
data: {
type: string
},
page: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<ExternalAuthListData>>(
'factory/baseExternalAccount/list_page',
null,
{
params: {
...data,
currentPage: page,
pageSize,
},
},
)
}
export function loadAccountTypesApi() {
return axios.get<never, BaseRespData<string[]>>(
'factory/baseExternalAccount/allCodelist',
)
}
export function getExternalAuthorisationByIdApi(id?: number | null) {
return axios.get<never, BaseRespData<ExternalAuthListData>>(
`factory/baseExternalAccount/get?id=${id}`,
)
}
export function deleteExternalAuthorisationApi(ids: string) {
return axios.get<never, BaseRespData<never>>(
`factory/baseExternalAccount/delete?ids=${ids}`,
)
}
export function addExternalAuthorisationApi(
url: string,
data: ExternalAuthListData,
) {
return axios.post<never, BaseRespData<never>>(url, data)
}
......@@ -34,10 +34,8 @@
<ElTableColumn v-else header-align="center" v-bind="col">
<template #header="{ column, $index }">
<component
:is="col.headerRender"
:is="() => col.headerRender(column, $index)"
v-if="col.headerRender"
:column="column"
:index="$index"
/>
<slot
v-else-if="col.headerSlot"
......@@ -54,10 +52,8 @@
<!-- 如果传递按钮数组,就展示按钮组 END-->
<!-- render函数 (START) 使用内置的component组件可以支持h函数渲染和txs语法-->
<component
:is="col.render"
:is="() => col.render(row, $index)"
v-if="col.render"
:row="row"
:index="$index"
/>
<slot
v-else-if="col.slot"
......
......@@ -13,7 +13,7 @@ import Error from '@/views/error/404.vue'
import OrderList from '@/views/order/index.vue'
import ProductionComplete from '@/views/production/complete.vue'
import { getToken } from '@/api/axios'
import UserPage from '@/views/UserPage.vue'
import UserPage from '@/views/system/UserPage.vue'
import DeliveryNotePage from '@/views/DeliveryNotePage.vue'
import AccountStatementNote from '@/views/AccountStatementNote.vue'
// import Product from '@/views/product/index.vue'
......@@ -27,6 +27,7 @@ import WarehouseManage from '@/views/warehouse/manage.vue'
import WarehouseWarning from '@/views/warehouse/warning.vue'
import WarehousePosition from '@/views/warehouse/position.vue'
import receiptDoc from '@/views/warehouse/receiptDoc.vue'
import ExternalAuthorisationPage from '@/views/system/externalAuthorisationPage.vue'
// import issueDoc from '@/views/warehouse/issueDoc.vue'
const router = createRouter({
history: createWebHistory(),
......@@ -93,6 +94,13 @@ const router = createRouter({
component: UserPage,
},
{
path:'/system/external-authorisation',
meta: {
title:'外部授权'
},
component: ExternalAuthorisationPage
},
{
path: '/system/delivery-note',
meta: {
title: '定制发货单',
......
......@@ -165,6 +165,11 @@ const menu: MenuItem[] = [
id: 4,
label: '用户管理',
},
{
index: '/system/external-authorisation',
id: 5,
label: '外部授权',
},
],
},
......
export interface ExternalAuthListData {
id?: number
account?: string
password?: string
supperMark?: number
factoryId?: number
factoryCode?: number
status?: number
createTime?: string
accountType?: string
accountDefault?: string
defaultType?: boolean
type?: string
appKey?: string
appSecret?: string
token?: string
refreshToken?: string
refreshTokenFailureTime?: string
}
<template>
<div class="user-page flex-column card h-100 overflow-hidden">
<div class="header-filter-form">
<ElForm :model="searchForm" inline>
<ElFormItem label="用户名" prop="account">
<ElInput
v-model="searchForm.account"
placeholder="请输入用户名"
clearable
style="width: 200px"
/>
</ElFormItem>
<ElFormItem label="状态" prop="status">
<ElSelect
v-model="searchForm.status"
clearable
style="width: 200px"
placeholder="请选择状态"
>
<ElOption label="启用" :value="1"></ElOption>
<ElOption label="禁用" :value="0"></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search">查询</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="success" @click="addUser">新增</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="danger" @click="deleteUser">删除</ElButton>
</ElFormItem>
</ElForm>
</div>
<div class="user-content flex-1 flex-column overflow-hidden">
<div class="user-list flex-1 overflow-hidden">
<ElTable
:data="tableData"
default-expand-all
style="width: 100%; height: 100%"
@selection-change="handleSelectionChange"
>
<ElTableColumn
type="selection"
header-align="center"
align="center"
width="55"
/>
<ElTableColumn
type="index"
header-align="center"
align="center"
label="序号"
width="55"
/>
<ElTableColumn prop="account" header-align="center" label="用户名">
<template #default="scope">
<div>
<span
>{{ scope.row.account }}
<ElTooltip
v-if="scope.row.supperMark === 1"
content="超级管理员"
placement="top"
>
<Icon
v-if="scope.row.supperMark === 1"
name="zu54"
style="vertical-align: super; cursor: pointer"
>
</Icon>
</ElTooltip>
</span>
</div>
</template>
</ElTableColumn>
<ElTableColumn
prop="factoryCode"
header-align="center"
label="工厂"
align="center"
/>
<ElTableColumn
prop="status"
header-align="center"
align="center"
label="状态"
>
<template #default="scope">
<el-tooltip
:content="scope.row.status ? '启用' : '禁用'"
placement="top"
>
<ElSwitch
v-model="scope.row.status"
:active-value="1"
:inactive-value="0"
@change="(e:number) => onChangeStatus(e, scope.row)"
></ElSwitch>
</el-tooltip>
</template>
</ElTableColumn>
<ElTableColumn
label="操作"
width="130"
header-align="center"
align="center"
>
<template #default="scope">
<el-icon
size="24"
title="编辑"
color="#EF6C00"
style="cursor: pointer; vertical-align: middle"
@click="editUser(scope.row)"
>
<Edit />
</el-icon>
</template>
</ElTableColumn>
</ElTable>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</div>
</div>
<ElDialog
v-model="dialogVisible"
:title="editId ? '编辑用户' : '新增用户'"
width="600px"
:close-on-click-modal="false"
@opened="onOpenedUserForm"
>
<div class="dialog-form">
<ElForm
ref="editFormRef"
:model="editForm"
:rules="rules"
label-width="90px"
>
<ElFormItem label="用户名" prop="account">
<ElInput
v-model="editForm.account"
placeholder="请输入用户名"
clearable
/>
</ElFormItem>
<ElFormItem v-if="!editId" label="密码" prop="password">
<ElInput
v-model="editForm.password"
placeholder="请输入密码"
clearable
type="password"
autocomplete="off"
:show-password="true"
/>
</ElFormItem>
<ElFormItem label="状态" prop="status">
<ElCheckbox
v-model="editForm.status"
label="启用"
true-value="1"
false-value="0"
></ElCheckbox>
</ElFormItem>
<ElFormItem label="角色" prop="supperMark">
<ElCheckbox
v-model="editForm.supperMark"
label="超级管理员"
true-value="1"
false-value="0"
></ElCheckbox>
</ElFormItem>
</ElForm>
</div>
<template #footer>
<div class="dialog-footer">
<ElButton @click="dialogVisible = false"> 取消 </ElButton>
<ElButton type="primary" @click="save">保存</ElButton>
</div>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import {
getUserList,
addUserApi,
updateUserApi,
deleteUserApi,
getDetailsByIdApi,
changeUserStatusApi,
} from '@/api/auth'
import Icon from '@/components/Icon.vue'
import { UserEditForm, userData, userSearchForm } from '@/types/api/user'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import { showConfirm } from '@/utils/ui'
import { Edit } from '@element-plus/icons-vue'
import type { FormRules } from 'element-plus'
import { reactive, ref } from 'vue'
const [searchForm, resetSearchForm] = useValue<userSearchForm>({})
const [editForm, resetEditForm] = useValue<UserEditForm>({
account: '',
password: '',
supperMark: '0',
status: '1',
})
const {
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
getUserList(searchForm.value, page, pageSize).then((res) => res.data),
})
const dialogVisible = ref(false)
const editFormRef = ref()
const selection = ref<userData[]>([])
const rules = reactive<FormRules<UserEditForm>>({
account: [
{
required: true,
message: '请输入用户名',
},
],
password: [
{
required: true,
message: '请输入密码',
},
],
})
const editId = ref<number | undefined>(undefined)
const addUser = () => {
editId.value = undefined
dialogVisible.value = true
resetEditForm()
}
const deleteUser = async () => {
if (!selection.value.length) {
return ElMessage({
message: '请选择用户',
type: 'warning',
offset: window.innerHeight / 2,
})
}
try {
await showConfirm('是否删除用户', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
})
} catch {
return
}
try {
const ids = selection.value.map((item) => item.id).join(',')
await deleteUserApi(ids)
ElMessage({
message: '删除成功',
type: 'success',
offset: window.innerHeight / 2,
})
search()
} catch (e) {
search()
// showError(e)
}
}
const editUser = async (item: userData) => {
editId.value = item.id
try {
const res = await getDetailsByIdApi(item.id)
res.data.supperMark = res.data.supperMark + ''
res.data.status = res.data.status + ''
editForm.value = res.data
dialogVisible.value = true
} catch (e) {
//showError(e)
}
}
const save = async () => {
try {
await editFormRef.value.validate()
} catch {
return
}
try {
if (!editId.value) {
await addUserApi({
...editForm.value,
supperMark: Number(editForm.value.supperMark),
status: Number(editForm.value.status),
})
} else {
await updateUserApi({
...editForm.value,
supperMark: Number(editForm.value.supperMark),
status: Number(editForm.value.status),
})
}
ElMessage({
message: '保存成功',
type: 'success',
offset: window.innerHeight / 2,
})
dialogVisible.value = false
search()
} catch (e) {
return
}
}
const onOpenedUserForm = async () => {
editFormRef.value?.clearValidate()
}
const handleSelectionChange = (s: userData[]) => {
selection.value = s
}
const onChangeStatus = async (value: number, item: userData) => {
try {
const res = await changeUserStatusApi(value, item.id)
ElMessage({
message: res.message,
type: 'success',
offset: window.innerHeight / 2,
})
search()
} catch (e) {
//showError(e)
}
}
</script>
<style lang="scss" scoped>
.header-filter-form {
margin-bottom: 20px;
:deep(.el-form-item) {
margin-right: 14px;
margin-bottom: 10px;
}
}
.user-operate-btn {
margin-bottom: 10px;
}
.dialog-footer {
text-align: center;
}
</style>
<template>
<div class="external-auth-page flex-column card h-100 overflow-hidden">
<div class="header-filter-form">
<ElForm v-enter-submit="search" :inline="true">
<ElFormItem label="账号类型">
<ElSelect
v-model="searchForm.type"
clearable
style="width: 180px"
placeholder="请选择"
>
<ElOption
v-for="(item, index) in accountTypes"
:key="index"
:label="item"
:value="item"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem label="">
<ElButton type="primary" @click="search"> 查询 </ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="success" @click="addDialog"> 新增 </ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="danger" @click="deleteSection(null)"> 删除 </ElButton>
</ElFormItem>
</ElForm>
</div>
<div class="external-auth-content flex-1 flex-column overflow-hidden">
<div class="external-auth-list flex-1 overflow-hidden">
<tableView
:selectionable="true"
:paginated-data="tableData"
:columns="tableColumns"
@selection-change="handleSelectionChange"
></tableView>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</div>
</div>
<ElDialog
v-model="dialogVisible"
:title="!!editId ? '新增' : '编辑'"
:close-on-click-modal="false"
width="600px"
@opened="handleOpened"
>
<ElForm
ref="editFormRef"
label-position="right"
label-width="110px"
:model="editForm"
>
<ElFormItem
label="账号类型"
prop="type"
:rules="[{ required: true, message: '请选择账号类型' }]"
>
<ElSelect
v-model="editForm.type"
style="width: 100%"
placeholder="请选择"
clearable
>
<ElOption
v-for="(item, index) in accountTypes"
:key="index"
:label="item"
:value="item"
></ElOption>
</ElSelect>
</ElFormItem>
<ElFormItem
label="账号"
prop="account"
:rules="[{ required: true, message: '请输入账号' }]"
>
<ElInput
v-model="editForm.account"
clearable
placeholder="请输入"
></ElInput>
</ElFormItem>
<ElFormItem label="是否默认" prop="defaultType">
<ElRadioGroup v-model="editForm.defaultType" clearable>
<ElRadio :label="true"></ElRadio>
<ElRadio :label="false"></ElRadio>
</ElRadioGroup>
</ElFormItem>
<ElFormItem
v-if="editForm.type === 'RIIN' && editForm.type"
label="授权操作指引"
>
<el-image
style="width: 100px; height: 100px"
src="https://jomalls-test.oss-cn-hangzhou.aliyuncs.com/riin-demo.png"
:zoom-rate="1.2"
:max-scale="7"
:min-scale="0.2"
:preview-src-list="[
'https://jomalls-test.oss-cn-hangzhou.aliyuncs.com/riin-demo.png',
]"
show-progress
:initial-index="4"
/>
</ElFormItem>
<ElFormItem
v-if="editForm.type !== 'RIIN' && editForm.type"
label="appKey"
prop="appKey"
:rules="[{ required: true, message: '请输入appKey' }]"
>
<ElInput
v-model="editForm.appKey"
clearable
placeholder="请输入"
></ElInput>
</ElFormItem>
<ElFormItem
v-if="editForm.type === 'RIIN' && editForm.type"
label="appSecret"
prop="appSecret"
:rules="[{ required: true, message: '请输入appSecret' }]"
>
<ElInput
v-model="editForm.appSecret"
clearable
placeholder="请输入"
></ElInput>
</ElFormItem>
<ElFormItem
v-if="editForm.type !== 'RIIN' && editForm.type"
label="token"
prop="token"
:rules="[{ required: true, message: '请输入token' }]"
>
<ElInput
v-model="editForm.token"
clearable
placeholder="请输入"
></ElInput>
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
<ElButton @click="dialogVisible = false"> 取消 </ElButton>
<ElButton type="primary" @click="submit"> 确认 </ElButton>
</div>
</template>
</ElDialog>
</template>
<script setup lang="tsx">
import { computed, ref, onMounted } from 'vue'
import TableView from '@/components/TableView.vue'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import {
getExternalAuthorisationListApi,
loadAccountTypesApi,
addExternalAuthorisationApi,
getExternalAuthorisationByIdApi,
deleteExternalAuthorisationApi,
} from '@/api/externalAuth'
import { ExternalAuthListData } from '@/types/api/externalAuth'
import { Delete, Edit } from '@element-plus/icons-vue'
const accountTypes = ref<string[]>([])
const searchForm = ref({
type: '',
})
const dialogVisible = ref(false)
const editId = ref<null | number>(null)
const [editForm, resetEditForm] = useValue<ExternalAuthListData>({
type: '',
defaultType: false,
appKey: '',
appSecret: '',
token: '',
account: '',
})
const tableColumns = computed(() => {
return [
{
label: '账号',
prop: 'account',
align: 'center',
},
{
label: '账号类型',
prop: 'type',
align: 'left',
},
{
label: '是否默认',
prop: 'defaultType',
width: 100,
align: 'center',
render: (item: ExternalAuthListData) => (
<el-checkbox
true-value={true}
false-value={false}
modelValue={item.defaultType}
disabled
></el-checkbox>
),
},
{
label: 'appKey',
prop: 'appKey',
align: 'left',
},
{ label: 'appSecret', prop: 'appSecret', align: 'left' },
{ label: 'token', prop: 'token', align: 'left' },
{ label: 'refreshToken', prop: 'refreshToken', align: 'left' },
{
label: 'refreshToken 过期时间',
prop: 'refreshTokenFailureTime',
},
{
label: '相关操作',
width: 100,
fixed: 'right',
align: 'center',
render: (item: ExternalAuthListData) => (
<div>
{
<span style="margin-right: 10px" title="编辑">
<el-icon
size="24"
title="编辑"
color="#EF6C00"
style="cursor: pointer"
onClick={() => editDialog(item)}
>
<Edit />
</el-icon>
</span>
}
{
<span title="删除">
<el-icon
size="24"
title="删除"
color="#f56c6c"
style="cursor: pointer"
onClick={() => deleteSection(item)}
>
<Delete />
</el-icon>
</span>
}
</div>
),
},
]
})
const {
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList({
query: (page, pageSize) =>
getExternalAuthorisationListApi(searchForm.value, page, pageSize).then(
(res) => res.data,
),
})
const loadAccountTypes = async () => {
try {
const res = await loadAccountTypesApi()
if (res.code !== 200) return
accountTypes.value = res.data
} catch (e) {
console.error(e)
}
}
const addDialog = () => {
editId.value = null
dialogVisible.value = true
resetEditForm()
}
const editDialog = async (item: ExternalAuthListData) => {
editId.value = item.id || null
try {
const res = await getExternalAuthorisationByIdApi(item.id || null)
if (res.code !== 200) return
editForm.value = res.data
dialogVisible.value = true
} catch (e) {
console.error(e)
}
}
const editFormRef = ref()
const deleteSection = async (item: ExternalAuthListData | null) => {
if (!item) {
if (selectedRows.value.length === 0) {
ElMessage.warning('请选择要删除的账号')
return
}
}
const ids = item ? [item.id] : selectedRows.value.map((item) => item.id)
try {
await ElMessageBox.confirm('确定删除所选账号吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
} catch {
return
}
try {
const res = await deleteExternalAuthorisationApi(ids.join(','))
if (res.code !== 200) return
ElMessage.success('删除成功')
search()
} catch (e) {
console.error(e)
}
}
const submit = async () => {
try {
await editFormRef.value.validate()
} catch {
return
}
const url = editId.value
? 'factory/baseExternalAccount/update'
: 'factory/baseExternalAccount/add'
try {
const res = await addExternalAuthorisationApi(url, editForm.value)
if (res.code !== 200) return
dialogVisible.value = false
search()
} catch (e) {
console.error(e)
}
}
const handleOpened = () => {
editFormRef.value.clearValidate()
}
const selectedRows = ref<ExternalAuthListData[]>([])
const handleSelectionChange = (val: ExternalAuthListData[]) => {
selectedRows.value = val
}
onMounted(() => {
loadAccountTypes()
})
</script>
<style lang="scss" scoped>
.header-filter-form {
margin-bottom: 20px;
:deep(.el-form-item) {
margin-right: 14px;
margin-bottom: 10px;
}
}
.dialog-footer {
text-align: center;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment