| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816 |
- <!-- @Author: Antigravity -->
- <template>
- <div class="p-2">
- <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
- :leave-active-class="proxy?.animate.searchAnimate.leave">
- <div v-show="showSearch" class="search">
- <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="85px">
- <el-form-item label="姓名" prop="name">
- <el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter="handleQuery" />
- </el-form-item>
- <el-form-item label="手机号" prop="phone">
- <el-input v-model="queryParams.phone" placeholder="请输入手机号" clearable @keyup.enter="handleQuery" />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
- <el-button icon="Refresh" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
- </div>
- </transition>
- <el-card shadow="never">
- <template #header>
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button v-hasPermi="['employee:employee:add']" type="primary" icon="Plus"
- @click="handleAdd">新增</el-button>
- </el-col>
- <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
- </el-row>
- </template>
- <el-table v-loading="loading" :data="employeeList" border @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="序号" align="center" width="70" type="index" />
- <el-table-column label="姓名" align="center" prop="name" min-width="120" />
- <el-table-column label="头像" align="center" width="80">
- <template #default="scope">
- <el-avatar :size="36" :src="scope.row.avatarUrl" icon="UserFilled" />
- </template>
- </el-table-column>
- <el-table-column label="手机" align="center" prop="phone" width="140" />
- <el-table-column label="注册时间" align="center" prop="createTime" width="170" />
- <el-table-column label="状态" align="center" width="100">
- <template #default="scope">
- <el-switch v-if="checkPermi(['employee:employee:changeStatus'])" v-model="scope.row._statusActive"
- :loading="scope.row._statusLoading" inline-prompt @change="handleStatusChange(scope.row)" />
- <el-tag v-else :type="scope.row.status === '0' ? 'danger' : 'success'">
- {{ scope.row.status === '0' ? '禁用' : '启用' }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160">
- <template #default="scope">
- <el-button v-hasPermi="['employee:employee:auth']" link type="success" icon="User"
- @click="handleAuth(scope.row)">授权</el-button>
- <el-button v-hasPermi="['employee:employee:query']" link type="primary" icon="View"
- @click="handleDetail(scope.row)">详情</el-button>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
- v-model:limit="queryParams.pageSize" @pagination="getList" />
- </el-card>
- <!-- 授权客户对话框 -->
- <SelectClientDialog v-model="authDialog.visible" v-model:selected-clients="selectedAuthClients" title="授权客户"
- selected-label="已授权" placeholder-text="输入客户名称搜索并添加授权客户" confirm-text="确认授权" :search-results="authSearchResults"
- :search-loading="authSearchLoading" :confirm-loading="buttonLoading" :searched="authSearched"
- @search="handleAuthSearch" @confirm="confirmAuth" />
- <!-- 新增员工对话框 -->
- <el-dialog v-model="addDialog.visible" title="新增员工" width="520px" append-to-body @close="resetAddForm"
- class="add-employee-dialog">
- <div class="add-form-wrapper">
- <!-- 头像区 -->
- <div class="add-avatar-area">
- <el-upload class="add-avatar-uploader" :action="uploadUrl" :headers="uploadHeaders" :show-file-list="false"
- :on-success="handleAddAvatarSuccess" :before-upload="beforeAddAvatarUpload">
- <div class="add-avatar-mask">
- <img v-if="addForm.avatarUrl" :src="addForm.avatarUrl" class="add-avatar-img" />
- <el-icon v-else class="add-avatar-placeholder">
- <UserFilled />
- </el-icon>
- <div class="add-avatar-overlay">
- <el-icon>
- <Camera />
- </el-icon>
- <span>更换头像</span>
- </div>
- </div>
- </el-upload>
- <p class="add-avatar-tip">点击上传员工头像</p>
- </div>
- <el-form ref="addFormRef" :model="addForm" :rules="addFormRules" label-position="top" class="add-form">
- <el-form-item label="姓名" prop="name">
- <el-input v-model="addForm.name" placeholder="请输入员工姓名" clearable maxlength="30" size="large" />
- </el-form-item>
- <el-form-item label="电话(登录账号)" prop="phone">
- <el-input v-model="addForm.phone" placeholder="请输入手机号作为登录账号" clearable maxlength="11" size="large" />
- </el-form-item>
- <el-form-item label="授权客户">
- <div class="add-auth-wrap">
- <div v-if="addSelectedClients.length > 0" class="add-auth-tags">
- <el-tag v-for="(client, idx) in addSelectedClients" :key="idx" closable size="large"
- @close="removeAddClient(idx)" class="add-auth-tag">
- <span class="add-auth-tag-index">{{ idx + 1 }}</span>
- {{ client.name }}
- </el-tag>
- </div>
- <el-button class="add-auth-btn" @click="openAddSelectClient">
- <el-icon>
- <Plus />
- </el-icon>
- {{ addSelectedClients.length > 0 ? '继续添加' : '选择客户' }}
- </el-button>
- </div>
- </el-form-item>
- </el-form>
- </div>
- <template #footer>
- <div class="add-dialog-footer">
- <el-button size="large" @click="addDialog.visible = false">取 消</el-button>
- <el-button size="large" type="primary" :loading="addBtnLoading" @click="confirmAdd">确认新增</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 新增员工-选择授权客户子对话框 -->
- <SelectClientDialog v-model="selectClientVisible" v-model:selected-clients="addSelectedClients"
- :search-results="selectClientResults" :search-loading="selectClientLoading" :searched="selectClientSearched"
- @search="handleSelectClientSearch" @confirm="selectClientVisible = false" />
- <!-- 员工详情对话框 -->
- <el-dialog v-model="detailDialog.visible" title="员工详情" width="680px" append-to-body>
- <template v-if="detailDialog.data">
- <div class="detail-header">
- <el-avatar :size="72" :src="detailDialog.data.avatarUrl" icon="UserFilled" class="detail-avatar" />
- <div class="detail-name-box">
- <text class="detail-name">{{ detailDialog.data.name }}</text>
- <el-tag :type="detailDialog.data.status === '0' ? 'danger' : 'success'" size="small"
- class="detail-status-tag">
- {{ detailDialog.data.status === '0' ? '已禁用' : '已启用' }}
- </el-tag>
- </div>
- </div>
- <div class="detail-divider"></div>
- <el-descriptions :column="2" border size="small" class="detail-descriptions">
- <el-descriptions-item label="员工ID">{{ detailDialog.data.id }}</el-descriptions-item>
- <el-descriptions-item label="手机号">{{ detailDialog.data.phone || '-' }}</el-descriptions-item>
- <el-descriptions-item label="注册时间">{{ detailDialog.data.createTime }}</el-descriptions-item>
- </el-descriptions>
- <div class="section-title">授权客户</div>
- <div v-if="detailDialog.data.authClientList && detailDialog.data.authClientList.length > 0">
- <div class="auth-client-card" v-for="(client, idx) in detailDialog.data.authClientList" :key="idx">
- <span class="client-index">{{ idx + 1 }}</span>
- <div class="client-info">
- <div class="client-row"><span class="client-label">名称</span><span class="client-value">{{ client.name
- }}</span></div>
- <div class="client-row"><span class="client-label">类型</span><span class="client-value">{{
- client.clientClass || '-' }}</span></div>
- <div class="client-row"><span class="client-label">加入时间</span><span class="client-value">{{
- client.enterDate || '-' }}</span></div>
- </div>
- </div>
- </div>
- <el-empty v-else description="暂无授权客户" :image-size="60" />
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup name="Customer" lang="ts">
- import { listEmployee, addEmployee, getEmployeeDetail, authEmployee, changeEmployeeStatus } from '@/api/system/employee';
- import { EmployeeVO, EmployeeQuery, EmployeeForm, ErpClientBriefVO } from '@/api/system/employee/types';
- import { searchErpClient, getErpClientByIds } from '@/api/erp/client';
- import { ErpClientVO } from '@/api/erp/client/types';
- import { checkPermi } from '@/utils/permission';
- import { globalHeaders } from '@/utils/request';
- import SelectClientDialog from './components/SelectClientDialog.vue';
- /** @Author: Antigravity */
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const employeeList = ref<EmployeeVO[]>([]);
- const buttonLoading = ref(false);
- const loading = ref(true);
- const showSearch = ref(true);
- const ids = ref<Array<string | number>>([]);
- const total = ref(0);
- const queryFormRef = ref<ElFormInstance>();
- // 授权客户对话框相关
- const authDialog = reactive({
- visible: false,
- employeeId: undefined as string | number | undefined
- });
- const authSearchLoading = ref(false);
- const authSearchResults = ref<ErpClientVO[]>([]);
- const authSearched = ref(false);
- const selectedAuthClients = ref<ErpClientVO[]>([]);
- // 详情对话框
- const detailDialog = reactive({
- visible: false,
- data: null as EmployeeVO | null
- });
- // 新增员工对话框
- const addDialog = reactive({
- visible: false
- });
- const addFormRef = ref<ElFormInstance>();
- const addForm = reactive({
- name: '',
- phone: '',
- avatar: undefined as string | undefined,
- avatarUrl: ''
- });
- const addFormRules = reactive({
- name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
- phone: [{ required: true, message: '手机号不能为空', trigger: 'blur' }]
- });
- const addBtnLoading = ref(false);
- const addSelectedClients = ref<ErpClientVO[]>([]);
- // 新增员工-选择授权客户子对话框
- const selectClientVisible = ref(false);
- const selectClientLoading = ref(false);
- const selectClientResults = ref<ErpClientVO[]>([]);
- const selectClientSearched = ref(false);
- const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload';
- const uploadHeaders = ref(globalHeaders());
- watch(() => authDialog.visible, (val) => {
- if (val) initAuthDialog();
- });
- const data = reactive<PageData<EmployeeForm, EmployeeQuery>>({
- form: {} as any,
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- name: undefined,
- phone: undefined,
- wechatOpenid: undefined
- },
- rules: {}
- });
- const { queryParams } = toRefs(data);
- /**
- * 处理列表数据,附加状态展示字段
- */
- const processList = (list: EmployeeVO[]) => {
- list.forEach(item => {
- (item as any)._statusActive = item.status !== '0';
- (item as any)._statusLoading = false;
- });
- };
- /** 查询员工列表 */
- const getList = async () => {
- loading.value = true;
- const res = await listEmployee(queryParams.value);
- const rows = res.rows as EmployeeVO[] || [];
- processList(rows);
- employeeList.value = rows;
- total.value = res.total;
- loading.value = false;
- };
- /** 搜索按钮操作 */
- const handleQuery = () => {
- queryParams.value.pageNum = 1;
- getList();
- };
- /** 重置按钮操作 */
- const resetQuery = () => {
- queryFormRef.value?.resetFields();
- handleQuery();
- };
- /** 多选框选中数据 */
- const handleSelectionChange = (selection: EmployeeVO[]) => {
- ids.value = selection.map((item) => item.id);
- };
- /** 状态切换 */
- const handleStatusChange = async (row: EmployeeVO & { _statusActive: boolean; _statusLoading: boolean }) => {
- const newStatus = row._statusActive ? '1' : '0';
- try {
- row._statusLoading = true;
- await changeEmployeeStatus(row.id, newStatus);
- proxy?.$modal.msgSuccess(newStatus === '1' ? '已启用' : '已禁用');
- } catch (e: any) {
- // 失败回滚状态
- row._statusActive = !row._statusActive;
- proxy?.$modal.msgError(e?.msg || '操作失败');
- } finally {
- row._statusLoading = false;
- }
- };
- /** 授权员工按钮操作 */
- const handleAuth = (row: EmployeeVO) => {
- authDialog.employeeId = row.id;
- authDialog.visible = true;
- };
- /** 弹窗打开时初始化 */
- const initAuthDialog = async () => {
- authSearchResults.value = [];
- authSearched.value = false;
- selectedAuthClients.value = [];
- if (!authDialog.employeeId) return;
- try {
- const res = await getEmployeeDetail(authDialog.employeeId);
- const ids = res.data?.authClientFRowIDs;
- if (ids) {
- selectedAuthClients.value = await fetchClientsByIds(ids);
- }
- } catch (e) {
- console.error('加载已授权客户失败', e);
- }
- };
- /** 搜索ERP客户 */
- const handleAuthSearch = async (keyword: string) => {
- if (!keyword) {
- proxy?.$modal.msgWarning('请输入客户名称');
- return;
- }
- authSearchLoading.value = true;
- authSearched.value = true;
- try {
- const res = await searchErpClient(keyword);
- authSearchResults.value = res.data || [];
- } catch (e) {
- authSearchResults.value = [];
- } finally {
- authSearchLoading.value = false;
- }
- };
- /** 确认授权 */
- const confirmAuth = async () => {
- if (!selectedAuthClients.value || selectedAuthClients.value.length === 0) {
- proxy?.$modal.msgError('请至少选择一个ERP客户');
- return;
- }
- buttonLoading.value = true;
- try {
- const authClientFRowIDs = selectedAuthClients.value.map(c => c.rowId).join(',');
- await authEmployee(authDialog.employeeId!, authClientFRowIDs);
- proxy?.$modal.msgSuccess('授权成功');
- authDialog.visible = false;
- getList();
- } finally {
- buttonLoading.value = false;
- }
- };
- /** 查看员工详情 */
- const handleDetail = async (row: EmployeeVO) => {
- detailDialog.visible = true;
- detailDialog.data = null;
- try {
- const res = await getEmployeeDetail(row.id);
- const data = res.data;
- if (data && data.authClientFRowIDs) {
- data.authClientList = await fetchClientsByIds(data.authClientFRowIDs) as any;
- }
- detailDialog.data = data;
- } catch (e) {
- proxy?.$modal.msgError('获取员工详情失败');
- detailDialog.visible = false;
- }
- };
- /** 新增按钮操作 */
- const handleAdd = () => {
- resetAddForm();
- addDialog.visible = true;
- };
- /** 重置新增表单 */
- const resetAddForm = () => {
- addForm.name = '';
- addForm.phone = '';
- addForm.avatar = undefined;
- addForm.avatarUrl = '';
- addSelectedClients.value = [];
- addFormRef.value?.resetFields();
- };
- /** 打开选择授权客户子对话框 */
- const openAddSelectClient = () => {
- selectClientVisible.value = true;
- };
- /** 搜索客户 */
- const handleSelectClientSearch = async (keyword: string) => {
- if (!keyword) {
- proxy?.$modal.msgWarning('请输入客户名称');
- return;
- }
- selectClientLoading.value = true;
- selectClientSearched.value = true;
- try {
- const res = await searchErpClient(keyword);
- selectClientResults.value = res.data || [];
- } catch (e) {
- selectClientResults.value = [];
- } finally {
- selectClientLoading.value = false;
- }
- };
- /** 头像上传成功回调 */
- const handleAddAvatarSuccess = (res: any) => {
- if (res.code === 200) {
- addForm.avatar = res.data.ossId;
- addForm.avatarUrl = res.data.url;
- } else {
- proxy?.$modal.msgError(res.msg || '上传失败');
- }
- };
- /** 头像上传前校验 */
- const beforeAddAvatarUpload = (file: any) => {
- const isImg = file.type.indexOf('image/') > -1;
- if (!isImg) {
- proxy?.$modal.msgError('请上传图片格式文件');
- return false;
- }
- const isLt5M = file.size / 1024 / 1024 < 5;
- if (!isLt5M) {
- proxy?.$modal.msgError('上传头像图片大小不能超过 5MB!');
- return false;
- }
- return true;
- };
- /** 确认新增员工 */
- const confirmAdd = async () => {
- const valid = await addFormRef.value?.validate().catch(() => false);
- if (!valid) return;
- addBtnLoading.value = true;
- try {
- const data: EmployeeForm = {
- name: addForm.name,
- phone: addForm.phone,
- password: '123456',
- authClientFRowIDs: addSelectedClients.value.map(c => c.rowId).join(',')
- };
- if (addForm.avatar) {
- data.avatar = addForm.avatar;
- }
- await addEmployee(data);
- proxy?.$modal.msgSuccess('新增成功');
- addDialog.visible = false;
- getList();
- } finally {
- addBtnLoading.value = false;
- }
- };
- /**
- * 根据 authClientFRowIDs 逗号分隔字符串,调用 ERP 批量接口反查客户列表
- */
- const fetchClientsByIds = async (authClientFRowIDs: string): Promise<ErpClientVO[]> => {
- const ids = authClientFRowIDs.split(',').map(s => s.trim()).filter(Boolean);
- if (ids.length === 0) return [];
- try {
- const res = await getErpClientByIds(ids.join(','));
- return (res.data || []).map(c => ({
- ...c,
- num: (c as any).num || c.rowId
- }));
- } catch (e) {
- console.error('批量查询ERP客户失败', e);
- return [];
- }
- };
- onMounted(() => {
- getList();
- });
- </script>
- <style scoped>
- /* ========== 详情弹窗 ========== */
- .section-title {
- font-size: 14px;
- font-weight: 600;
- color: #303133;
- margin: 20px 0 12px 0;
- padding-left: 10px;
- border-left: 3px solid #C1001C;
- }
- :deep(.el-dialog .pagination-container) {
- display: flex !important;
- justify-content: center !important;
- background-color: transparent !important;
- padding: 20px 0 10px 0 !important;
- margin-top: 0 !important;
- }
- .detail-header {
- display: flex;
- align-items: center;
- gap: 24px;
- padding-bottom: 20px;
- }
- .detail-avatar {
- flex-shrink: 0;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
- }
- .detail-name-box {
- display: flex;
- align-items: center;
- gap: 12px;
- }
- .detail-name {
- font-size: 22px;
- font-weight: 600;
- color: #1d1d1f;
- letter-spacing: 0.5px;
- }
- .detail-status-tag {
- flex-shrink: 0;
- }
- .detail-divider {
- height: 1px;
- background: linear-gradient(90deg, #eee 0%, transparent 100%);
- margin-bottom: 20px;
- }
- .detail-descriptions {
- margin-bottom: 8px;
- }
- .auth-client-card {
- display: flex;
- align-items: flex-start;
- gap: 16px;
- background: #fafafa;
- border-radius: 12px;
- padding: 16px 20px;
- margin-bottom: 12px;
- border: 1px solid #f0f0f0;
- transition: box-shadow 0.2s;
- }
- .auth-client-card:hover {
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
- }
- .client-index {
- width: 28px;
- height: 28px;
- background: #C1001C;
- color: #fff;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 13px;
- font-weight: 600;
- flex-shrink: 0;
- margin-top: 2px;
- }
- .client-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- gap: 6px;
- }
- .client-row {
- display: flex;
- gap: 12px;
- font-size: 13px;
- }
- .client-label {
- color: #999;
- min-width: 60px;
- flex-shrink: 0;
- }
- .client-value {
- color: #333;
- font-weight: 500;
- }
- /* ========== 新增员工对话框 ========== */
- .add-employee-dialog :deep(.el-dialog__header) {
- padding: 24px 28px 0;
- margin: 0;
- }
- .add-employee-dialog :deep(.el-dialog__title) {
- font-size: 18px;
- font-weight: 600;
- color: #1a1a1a;
- letter-spacing: 0.3px;
- }
- .add-employee-dialog :deep(.el-dialog__body) {
- padding: 12px 28px 20px;
- }
- .add-form-wrapper {
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .add-avatar-area {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-bottom: 28px;
- }
- .add-avatar-uploader {
- cursor: pointer;
- }
- .add-avatar-mask {
- position: relative;
- width: 88px;
- height: 88px;
- border-radius: 50%;
- overflow: hidden;
- background: #f5f7fa;
- border: 2px solid #e8ecf1;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: border-color 0.3s, box-shadow 0.3s;
- }
- .add-avatar-mask:hover {
- border-color: #409eff;
- box-shadow: 0 0 0 4px rgba(64, 158, 255, 0.1);
- }
- .add-avatar-mask:hover .add-avatar-overlay {
- opacity: 1;
- }
- .add-avatar-img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- .add-avatar-placeholder {
- font-size: 36px;
- color: #c0c4cc;
- }
- .add-avatar-overlay {
- position: absolute;
- inset: 0;
- background: rgba(0, 0, 0, 0.45);
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 2px;
- opacity: 0;
- transition: opacity 0.3s;
- color: #fff;
- font-size: 11px;
- }
- .add-avatar-overlay .el-icon {
- font-size: 18px;
- }
- .add-avatar-tip {
- margin: 10px 0 0;
- font-size: 12px;
- color: #b0b5be;
- letter-spacing: 0.2px;
- }
- .add-form {
- width: 100%;
- }
- .add-form :deep(.el-form-item__label) {
- font-size: 13px;
- font-weight: 500;
- color: #4a4f5a;
- padding-bottom: 6px;
- }
- .add-form :deep(.el-input--large .el-input__wrapper) {
- border-radius: 8px;
- box-shadow: 0 0 0 1px #e4e7ed inset;
- transition: box-shadow 0.25s;
- }
- .add-form :deep(.el-input--large .el-input__wrapper:hover) {
- box-shadow: 0 0 0 1px #c6cacf inset;
- }
- .add-form :deep(.el-input--large.is-focus .el-input__wrapper) {
- box-shadow: 0 0 0 1px #409eff inset, 0 0 0 3px rgba(64, 158, 255, 0.08);
- }
- .add-auth-wrap {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 8px;
- }
- .add-auth-tags {
- display: flex;
- flex-wrap: wrap;
- gap: 6px;
- }
- .add-auth-tag {
- font-size: 13px;
- border-radius: 6px;
- padding: 6px 12px;
- border: none;
- background: #f0f5ff;
- color: #3370ff;
- }
- .add-auth-tag :deep(.el-tag__close) {
- color: #8fa8e0;
- }
- .add-auth-tag :deep(.el-tag__close:hover) {
- background: rgba(51, 112, 255, 0.12);
- color: #3370ff;
- }
- .add-auth-tag-index {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 18px;
- height: 18px;
- border-radius: 50%;
- background: #3370ff;
- color: #fff;
- font-size: 11px;
- font-weight: 600;
- margin-right: 6px;
- }
- .add-auth-btn {
- flex-shrink: 0;
- border-radius: 6px;
- border: 1px dashed #c0c4cc;
- background: #fff;
- color: #606266;
- font-size: 13px;
- padding: 8px 16px;
- transition: border-color 0.25s, color 0.25s, background 0.25s;
- }
- .add-auth-btn:hover {
- border-color: #409eff;
- color: #409eff;
- background: #f0f5ff;
- }
- .add-dialog-footer {
- display: flex;
- justify-content: flex-end;
- gap: 12px;
- padding-top: 4px;
- }
- .add-dialog-footer .el-button {
- border-radius: 8px;
- padding: 10px 28px;
- font-size: 14px;
- font-weight: 500;
- letter-spacing: 0.5px;
- }
- .add-dialog-footer .el-button--primary {
- box-shadow: 0 2px 8px rgba(64, 158, 255, 0.25);
- }
- .add-dialog-footer .el-button--primary:hover {
- box-shadow: 0 4px 16px rgba(64, 158, 255, 0.35);
- }
- </style>
|