Files
000-platform/frontend/src/views/tenants/index.vue
111 ab84f6b87d
All checks were successful
continuous-integration/drone/push Build is passing
feat: 企微应用租户下拉选择 + corp_id 自动填入
- 租户表增加 corp_id 字段(企业微信企业ID)
- 租户管理页面支持配置 corp_id
- 企微应用页面租户从下拉选择
- 选择租户后自动填入 corp_id 并禁用编辑
- 提示用户如租户未配置 corp_id 需先去配置
2026-01-24 10:20:02 +08:00

247 lines
7.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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="企业微信企业IDww开头" />
</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>