All checks were successful
continuous-integration/drone/push Build is passing
- 租户表增加 corp_id 字段(企业微信企业ID) - 租户管理页面支持配置 corp_id - 企微应用页面租户从下拉选择 - 选择租户后自动填入 corp_id 并禁用编辑 - 提示用户如租户未配置 corp_id 需先去配置
247 lines
7.6 KiB
Vue
247 lines
7.6 KiB
Vue
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import api from '@/api'
|
||
import { useAuthStore } from '@/stores/auth'
|
||
|
||
const router = useRouter()
|
||
const authStore = useAuthStore()
|
||
|
||
const loading = ref(false)
|
||
const tableData = ref([])
|
||
const total = ref(0)
|
||
const query = reactive({
|
||
page: 1,
|
||
size: 20,
|
||
status: '',
|
||
keyword: ''
|
||
})
|
||
|
||
// 对话框
|
||
const dialogVisible = ref(false)
|
||
const dialogTitle = ref('')
|
||
const editingId = ref(null)
|
||
const formRef = ref(null)
|
||
const form = reactive({
|
||
code: '',
|
||
name: '',
|
||
corp_id: '',
|
||
status: 'active',
|
||
expired_at: null,
|
||
contact_info: {
|
||
contact: '',
|
||
phone: '',
|
||
email: ''
|
||
}
|
||
})
|
||
|
||
const rules = {
|
||
code: [{ required: true, message: '请输入租户代码', trigger: 'blur' }],
|
||
name: [{ required: true, message: '请输入租户名称', trigger: 'blur' }]
|
||
}
|
||
|
||
async function fetchList() {
|
||
loading.value = true
|
||
try {
|
||
const res = await api.get('/api/tenants', { params: query })
|
||
tableData.value = res.data.items || []
|
||
total.value = res.data.total || 0
|
||
} catch (e) {
|
||
console.error(e)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
function handleSearch() {
|
||
query.page = 1
|
||
fetchList()
|
||
}
|
||
|
||
function handlePageChange(page) {
|
||
query.page = page
|
||
fetchList()
|
||
}
|
||
|
||
function handleCreate() {
|
||
editingId.value = null
|
||
dialogTitle.value = '新建租户'
|
||
Object.assign(form, {
|
||
code: '',
|
||
name: '',
|
||
corp_id: '',
|
||
status: 'active',
|
||
expired_at: null,
|
||
contact_info: { contact: '', phone: '', email: '' }
|
||
})
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
function handleEdit(row) {
|
||
editingId.value = row.id
|
||
dialogTitle.value = '编辑租户'
|
||
Object.assign(form, {
|
||
code: row.code,
|
||
name: row.name,
|
||
corp_id: row.corp_id || '',
|
||
status: row.status,
|
||
expired_at: row.expired_at,
|
||
contact_info: row.contact_info || { contact: '', phone: '', email: '' }
|
||
})
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
async function handleSubmit() {
|
||
await formRef.value.validate()
|
||
|
||
try {
|
||
if (editingId.value) {
|
||
await api.put(`/api/tenants/${editingId.value}`, form)
|
||
ElMessage.success('更新成功')
|
||
} else {
|
||
await api.post('/api/tenants', form)
|
||
ElMessage.success('创建成功')
|
||
}
|
||
dialogVisible.value = false
|
||
fetchList()
|
||
} catch (e) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
|
||
async function handleDelete(row) {
|
||
await ElMessageBox.confirm(`确定删除租户 "${row.name}" 吗?`, '提示', {
|
||
type: 'warning'
|
||
})
|
||
|
||
try {
|
||
await api.delete(`/api/tenants/${row.id}`)
|
||
ElMessage.success('删除成功')
|
||
fetchList()
|
||
} catch (e) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
|
||
function handleDetail(row) {
|
||
router.push(`/tenants/${row.id}`)
|
||
}
|
||
|
||
function getStatusType(status) {
|
||
const map = { active: 'success', expired: 'danger', trial: 'warning' }
|
||
return map[status] || 'info'
|
||
}
|
||
|
||
function getStatusText(status) {
|
||
const map = { active: '活跃', expired: '已过期', trial: '试用' }
|
||
return map[status] || status
|
||
}
|
||
|
||
onMounted(() => {
|
||
fetchList()
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div class="page-container">
|
||
<div class="page-header">
|
||
<div class="title">租户管理</div>
|
||
<el-button v-if="authStore.isOperator" type="primary" @click="handleCreate">
|
||
<el-icon><Plus /></el-icon>
|
||
新建租户
|
||
</el-button>
|
||
</div>
|
||
|
||
<!-- 搜索栏 -->
|
||
<div class="search-bar">
|
||
<el-input
|
||
v-model="query.keyword"
|
||
placeholder="搜索租户代码或名称"
|
||
clearable
|
||
style="width: 240px"
|
||
@keyup.enter="handleSearch"
|
||
/>
|
||
<el-select v-model="query.status" placeholder="状态" clearable style="width: 120px">
|
||
<el-option label="活跃" value="active" />
|
||
<el-option label="已过期" value="expired" />
|
||
<el-option label="试用" value="trial" />
|
||
</el-select>
|
||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||
</div>
|
||
|
||
<!-- 表格 -->
|
||
<el-table v-loading="loading" :data="tableData" style="width: 100%">
|
||
<el-table-column prop="id" label="ID" width="80" />
|
||
<el-table-column prop="code" label="代码" width="120" />
|
||
<el-table-column prop="name" label="名称" min-width="150" />
|
||
<el-table-column prop="corp_id" label="企业ID" width="200" show-overflow-tooltip />
|
||
<el-table-column prop="status" label="状态" width="100">
|
||
<template #default="{ row }">
|
||
<el-tag :type="getStatusType(row.status)" size="small">
|
||
{{ getStatusText(row.status) }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="expired_at" label="过期时间" width="120" />
|
||
<el-table-column prop="created_at" label="创建时间" width="180" />
|
||
<el-table-column label="操作" width="200" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button type="primary" link size="small" @click="handleDetail(row)">详情</el-button>
|
||
<el-button v-if="authStore.isOperator" type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
|
||
<el-button v-if="authStore.isOperator" type="danger" link size="small" @click="handleDelete(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<div style="margin-top: 20px; display: flex; justify-content: flex-end">
|
||
<el-pagination
|
||
v-model:current-page="query.page"
|
||
:page-size="query.size"
|
||
:total="total"
|
||
layout="total, prev, pager, next"
|
||
@current-change="handlePageChange"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 编辑对话框 -->
|
||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px">
|
||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||
<el-form-item label="租户代码" prop="code">
|
||
<el-input v-model="form.code" :disabled="!!editingId" placeholder="唯一标识" />
|
||
</el-form-item>
|
||
<el-form-item label="租户名称" prop="name">
|
||
<el-input v-model="form.name" placeholder="公司/组织名称" />
|
||
</el-form-item>
|
||
<el-form-item label="企业ID">
|
||
<el-input v-model="form.corp_id" placeholder="企业微信企业ID,ww开头" />
|
||
</el-form-item>
|
||
<el-form-item label="状态">
|
||
<el-select v-model="form.status" style="width: 100%">
|
||
<el-option label="活跃" value="active" />
|
||
<el-option label="试用" value="trial" />
|
||
<el-option label="已过期" value="expired" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="过期时间">
|
||
<el-date-picker v-model="form.expired_at" type="date" value-format="YYYY-MM-DD" style="width: 100%" />
|
||
</el-form-item>
|
||
<el-form-item label="联系人">
|
||
<el-input v-model="form.contact_info.contact" placeholder="联系人姓名" />
|
||
</el-form-item>
|
||
<el-form-item label="联系电话">
|
||
<el-input v-model="form.contact_info.phone" placeholder="联系电话" />
|
||
</el-form-item>
|
||
<el-form-item label="邮箱">
|
||
<el-input v-model="form.contact_info.email" placeholder="邮箱地址" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|