大屏页面初始化
This commit is contained in:
12
screen-vue/src/api/bizRole.js
Normal file
12
screen-vue/src/api/bizRole.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指标信息列表
|
||||||
|
*/
|
||||||
|
export function getHomeRoleList(params) {
|
||||||
|
return request({
|
||||||
|
url: '/biz/homeRole/list',
|
||||||
|
method: 'get',
|
||||||
|
params: params
|
||||||
|
})
|
||||||
|
}
|
||||||
310
screen-vue/src/components/Table/proFilterSelect.vue
Normal file
310
screen-vue/src/components/Table/proFilterSelect.vue
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
<template>
|
||||||
|
<div class="el-card el-card--border" ref="wrapperRef" style="height: 100%; border: none; box-shadow: none;">
|
||||||
|
<el-input
|
||||||
|
v-if="showSearch"
|
||||||
|
v-model="filterText"
|
||||||
|
:placeholder="searchPlaceholder"
|
||||||
|
clearable
|
||||||
|
class="filter-search-input"
|
||||||
|
@clear="handleClear"
|
||||||
|
size="default"
|
||||||
|
/>
|
||||||
|
<el-divider v-if="showSearch" direction="horizontal" class="filter-tree-divider" />
|
||||||
|
<div
|
||||||
|
class="list-container"
|
||||||
|
:style="{ height: listHeight, width: '100%', overflow: 'hidden' }"
|
||||||
|
>
|
||||||
|
<el-scrollbar height="100%" :native="true">
|
||||||
|
<div
|
||||||
|
class="list-item"
|
||||||
|
v-for="item in filteredList"
|
||||||
|
:key="item[nodeKey]"
|
||||||
|
@mouseenter="() => hoveredItemId = item[nodeKey]"
|
||||||
|
@mouseleave="() => handleItemLeave(item[nodeKey])"
|
||||||
|
@click="() => handleItemClick(item)"
|
||||||
|
:class="{ 'list-item--selected': selectedItemId === item[nodeKey] }"
|
||||||
|
>
|
||||||
|
<span class="item-text">{{ item[labelKey] }}</span>
|
||||||
|
<div class="action-wrapper" v-show="hoveredItemId === item[nodeKey]">
|
||||||
|
<el-dropdown
|
||||||
|
trigger="click"
|
||||||
|
placement="bottom"
|
||||||
|
:teleported="false"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<el-button size="mini" icon="MoreFilled" circle class="action-btn" />
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click="() => handleEdit(item)">
|
||||||
|
<el-icon class="menu-icon"><Edit /></el-icon>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="() => handleDelete(item)" divided>
|
||||||
|
<el-icon class="menu-icon"><Delete /></el-icon>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="() => handleView(item)">
|
||||||
|
<el-icon class="menu-icon"><View /></el-icon>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch, defineProps, defineEmits, withDefaults, onMounted, onUnmounted, nextTick, computed } from 'vue'
|
||||||
|
import { ElInput, ElDivider, ElScrollbar, ElDropdown, ElButton, ElDropdownMenu, ElDropdownItem, ElIcon } from 'element-plus'
|
||||||
|
import { Edit, Delete, View, MoreFilled, Search } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
export interface ListItem {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'edit',
|
||||||
|
'delete',
|
||||||
|
'view',
|
||||||
|
'item-click',
|
||||||
|
'search-change',
|
||||||
|
'search-clear'
|
||||||
|
])
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
listData: ListItem[]
|
||||||
|
showSearch?: boolean
|
||||||
|
searchPlaceholder?: string
|
||||||
|
nodeKey?: string
|
||||||
|
labelKey?: string
|
||||||
|
customFilter?: (value: string, data: ListItem) => boolean
|
||||||
|
autoHeight?: boolean
|
||||||
|
minHeight?: string | number
|
||||||
|
defaultValue?: string | number
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
showSearch: true,
|
||||||
|
searchPlaceholder: '请输入关键词过滤',
|
||||||
|
nodeKey: 'id',
|
||||||
|
labelKey: 'label',
|
||||||
|
autoHeight: true,
|
||||||
|
minHeight: '100px',
|
||||||
|
defaultValue: ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const filterText = ref('')
|
||||||
|
const wrapperRef = ref<HTMLDivElement>(null)
|
||||||
|
const hoveredItemId = ref<string | number | null>(null)
|
||||||
|
const selectedItemId = ref<string | number | null>(props.defaultValue)
|
||||||
|
|
||||||
|
const listHeight = computed(() => {
|
||||||
|
if (!props.autoHeight || !wrapperRef.value) return props.minHeight as string
|
||||||
|
const wrapperHeight = wrapperRef.value.clientHeight
|
||||||
|
const searchHeight = props.showSearch ? 40 : 0
|
||||||
|
const dividerHeight = props.showSearch ? (16 + 2) : 0
|
||||||
|
const baseMargin = 8
|
||||||
|
return `${wrapperHeight - searchHeight - dividerHeight - baseMargin}px`
|
||||||
|
})
|
||||||
|
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
if (!filterText.value) return props.listData
|
||||||
|
if (props.customFilter) {
|
||||||
|
return props.listData.filter(item => props.customFilter!(filterText.value, item))
|
||||||
|
}
|
||||||
|
return props.listData.filter(item => {
|
||||||
|
const label = item[props.labelKey] || ''
|
||||||
|
return label.toString().includes(filterText.value)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => filterText.value,
|
||||||
|
(val) => {
|
||||||
|
emit('search-change', val)
|
||||||
|
},
|
||||||
|
{ immediate: false }
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(() => props.defaultValue, (val) => {
|
||||||
|
selectedItemId.value = val
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
const handleItemLeave = (id: string | number) => {
|
||||||
|
hoveredItemId.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleItemClick = (item: ListItem) => {
|
||||||
|
selectedItemId.value = item[props.nodeKey]
|
||||||
|
emit('item-click', item)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEdit = (item: ListItem) => {
|
||||||
|
emit('edit', item)
|
||||||
|
hoveredItemId.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = (item: ListItem) => {
|
||||||
|
emit('delete', item)
|
||||||
|
hoveredItemId.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleView = (item: ListItem) => {
|
||||||
|
emit('view', item)
|
||||||
|
hoveredItemId.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClear = () => {
|
||||||
|
filterText.value = ''
|
||||||
|
emit('search-clear')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await nextTick()
|
||||||
|
const resizeHandler = () => void listHeight.value
|
||||||
|
|
||||||
|
window.addEventListener('resize', resizeHandler)
|
||||||
|
|
||||||
|
if (window.ResizeObserver && wrapperRef.value) {
|
||||||
|
const observer = new ResizeObserver(resizeHandler)
|
||||||
|
observer.observe(wrapperRef.value)
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
observer.disconnect()
|
||||||
|
window.removeEventListener('resize', resizeHandler)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
doFilter: (value: string) => {
|
||||||
|
filterText.value = value
|
||||||
|
},
|
||||||
|
clearSearch: handleClear,
|
||||||
|
getFilteredList: () => filteredList.value,
|
||||||
|
setSelected: (id: string | number) => {
|
||||||
|
selectedItemId.value = id
|
||||||
|
},
|
||||||
|
getSelected: () => {
|
||||||
|
return filteredList.value.find(item => item[props.nodeKey] === selectedItemId.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.el-card) {
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-search-input {
|
||||||
|
margin: 0 2px !important;
|
||||||
|
width: calc(100% - 4px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tree-divider {
|
||||||
|
margin: 2px 2px 0 2px !important;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 4px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
|
user-select: none;
|
||||||
|
--el-tree-node-content-hover-bg-color: #f0f9ff;
|
||||||
|
--el-tree-node-selected-bg-color: #e6f7ff;
|
||||||
|
--el-tree-node-selected-color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item:hover {
|
||||||
|
background-color: var(--el-tree-node-content-hover-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item--selected {
|
||||||
|
background-color: var(--el-tree-node-selected-bg-color) !important;
|
||||||
|
color: var(--el-tree-node-selected-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item--selected .item-text {
|
||||||
|
color: var(--el-tree-node-selected-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-wrapper {
|
||||||
|
position: relative;
|
||||||
|
z-index: 100;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
color: #909399 !important;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
color: #1890ff !important;
|
||||||
|
background-color: #f5f7fa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
color: #606266;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-dropdown-menu) {
|
||||||
|
min-width: 40px !important;
|
||||||
|
padding: 4px 0;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-dropdown-item) {
|
||||||
|
text-align: center;
|
||||||
|
padding: 6px 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-dropdown__popper) {
|
||||||
|
position: absolute !important;
|
||||||
|
top: 100% !important;
|
||||||
|
left: 50% !important;
|
||||||
|
margin-top: 4px !important;
|
||||||
|
transform: translateX(-50%) !important;
|
||||||
|
z-index: 9999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-scrollbar__wrap) {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
222
screen-vue/src/views/desktop/components/Alert.vue
Normal file
222
screen-vue/src/views/desktop/components/Alert.vue
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
<template>
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="main-card">
|
||||||
|
<div class="title-section">
|
||||||
|
<h1 class="title">预警信息</h1>
|
||||||
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="content-section">
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<el-table
|
||||||
|
:data="tableData"
|
||||||
|
border
|
||||||
|
:header-cell-style="{ background: '#f5f7fa' }"
|
||||||
|
style="width: 100%;"
|
||||||
|
height="100%"
|
||||||
|
v-loading="loading"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
label="姓名"
|
||||||
|
width="120"
|
||||||
|
fixed="left"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="age"
|
||||||
|
label="年龄"
|
||||||
|
width="80"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="gender"
|
||||||
|
label="性别"
|
||||||
|
width="80"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="phone"
|
||||||
|
label="手机号"
|
||||||
|
width="150"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="email"
|
||||||
|
label="邮箱"
|
||||||
|
width="200"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="address"
|
||||||
|
label="地址"
|
||||||
|
width="250"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="company"
|
||||||
|
label="公司"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="position"
|
||||||
|
label="职位"
|
||||||
|
width="150"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="salary"
|
||||||
|
label="薪资"
|
||||||
|
width="120"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="entryDate"
|
||||||
|
label="入职日期"
|
||||||
|
width="150"
|
||||||
|
fixed="right"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { ElTable, ElTableColumn, ElLoading } from 'element-plus'
|
||||||
|
|
||||||
|
// 生成模拟数据
|
||||||
|
const generateTableData = () => {
|
||||||
|
const data = []
|
||||||
|
const names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十']
|
||||||
|
const genders = ['男', '女']
|
||||||
|
const positions = ['前端开发', '后端开发', '产品经理', 'UI设计', '测试工程师', '运维工程师']
|
||||||
|
const companies = ['科技有限公司', '网络科技公司', '信息技术公司', '数据服务公司']
|
||||||
|
|
||||||
|
for (let i = 1; i <= 50; i++) {
|
||||||
|
data.push({
|
||||||
|
id: i,
|
||||||
|
name: names[Math.floor(Math.random() * names.length)] + i,
|
||||||
|
age: Math.floor(Math.random() * 30) + 20,
|
||||||
|
gender: genders[Math.floor(Math.random() * genders.length)],
|
||||||
|
phone: `13${Math.floor(Math.random() * 900000000) + 100000000}`,
|
||||||
|
email: `user${i}@example.com`,
|
||||||
|
address: `北京市朝阳区某某街道${Math.floor(Math.random() * 100)}号`,
|
||||||
|
company: Math.floor(Math.random() * 10) + '号' + companies[Math.floor(Math.random() * companies.length)],
|
||||||
|
position: positions[Math.floor(Math.random() * positions.length)],
|
||||||
|
salary: `${Math.floor(Math.random() * 30) + 10}k`,
|
||||||
|
entryDate: `202${Math.floor(Math.random() * 5) + 1}-${Math.floor(Math.random() * 12) + 1}-${Math.floor(Math.random() * 28) + 1}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableData = ref([])
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 模拟接口请求延迟
|
||||||
|
setTimeout(() => {
|
||||||
|
tableData.value = generateTableData()
|
||||||
|
loading.value = false
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-section {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper) {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
|
||||||
|
display: block;
|
||||||
|
height: 6px;
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar-track) {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar-thumb) {
|
||||||
|
background: #dcdfe6;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar-thumb:hover) {
|
||||||
|
background: #c0c4cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__fixed-left) {
|
||||||
|
box-shadow: 2px 0 6px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__fixed-right) {
|
||||||
|
box-shadow: -2px 0 6px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table th) {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
224
screen-vue/src/views/desktop/components/Note.vue
Normal file
224
screen-vue/src/views/desktop/components/Note.vue
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
<template>
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="main-card">
|
||||||
|
<div class="title-section">
|
||||||
|
<h1 class="title">便签信息</h1>
|
||||||
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="content-section">
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<el-table
|
||||||
|
:data="tableData"
|
||||||
|
border
|
||||||
|
:header-cell-style="{ background: '#f5f7fa' }"
|
||||||
|
style="width: 100%;"
|
||||||
|
height="100%"
|
||||||
|
v-loading="loading"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
label="姓名"
|
||||||
|
width="120"
|
||||||
|
fixed="left"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="age"
|
||||||
|
label="年龄"
|
||||||
|
width="80"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="gender"
|
||||||
|
label="性别"
|
||||||
|
width="80"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="phone"
|
||||||
|
label="手机号"
|
||||||
|
width="150"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="email"
|
||||||
|
label="邮箱"
|
||||||
|
width="200"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="address"
|
||||||
|
label="地址"
|
||||||
|
width="250"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="company"
|
||||||
|
label="公司"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="position"
|
||||||
|
label="职位"
|
||||||
|
width="150"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="salary"
|
||||||
|
label="薪资"
|
||||||
|
width="120"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="entryDate"
|
||||||
|
label="入职日期"
|
||||||
|
width="150"
|
||||||
|
fixed="right"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { ElTable, ElTableColumn, ElLoading } from 'element-plus'
|
||||||
|
|
||||||
|
// 生成模拟数据
|
||||||
|
const generateTableData = () => {
|
||||||
|
const data = []
|
||||||
|
const names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十']
|
||||||
|
const genders = ['男', '女']
|
||||||
|
const positions = ['前端开发', '后端开发', '产品经理', 'UI设计', '测试工程师', '运维工程师']
|
||||||
|
const companies = ['科技有限公司', '网络科技公司', '信息技术公司', '数据服务公司']
|
||||||
|
|
||||||
|
for (let i = 1; i <= 50; i++) {
|
||||||
|
data.push({
|
||||||
|
id: i,
|
||||||
|
name: names[Math.floor(Math.random() * names.length)] + i,
|
||||||
|
age: Math.floor(Math.random() * 30) + 20,
|
||||||
|
gender: genders[Math.floor(Math.random() * genders.length)],
|
||||||
|
phone: `13${Math.floor(Math.random() * 900000000) + 100000000}`,
|
||||||
|
email: `user${i}@example.com`,
|
||||||
|
address: `北京市朝阳区某某街道${Math.floor(Math.random() * 100)}号`,
|
||||||
|
company: Math.floor(Math.random() * 10) + '号' + companies[Math.floor(Math.random() * companies.length)],
|
||||||
|
position: positions[Math.floor(Math.random() * positions.length)],
|
||||||
|
salary: `${Math.floor(Math.random() * 30) + 10}k`,
|
||||||
|
entryDate: `202${Math.floor(Math.random() * 5) + 1}-${Math.floor(Math.random() * 12) + 1}-${Math.floor(Math.random() * 28) + 1}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableData = ref([])
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 模拟接口请求延迟
|
||||||
|
setTimeout(() => {
|
||||||
|
tableData.value = generateTableData()
|
||||||
|
loading.value = false
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-section {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格滚动条样式优化 */
|
||||||
|
:deep(.el-table__body-wrapper) {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
|
||||||
|
display: block;
|
||||||
|
height: 6px;
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar-track) {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar-thumb) {
|
||||||
|
background: #dcdfe6;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body-wrapper::-webkit-scrollbar-thumb:hover) {
|
||||||
|
background: #c0c4cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 固定表头样式优化 */
|
||||||
|
:deep(.el-table__fixed-left) {
|
||||||
|
box-shadow: 2px 0 6px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__fixed-right) {
|
||||||
|
box-shadow: -2px 0 6px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table th) {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
313
screen-vue/src/views/desktop/components/Quick.vue
Normal file
313
screen-vue/src/views/desktop/components/Quick.vue
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
<template>
|
||||||
|
<div class="quick-login-container">
|
||||||
|
<div class="main-card">
|
||||||
|
<div class="title-section">
|
||||||
|
<h1 class="title">快捷登录</h1>
|
||||||
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<div class="content-section">
|
||||||
|
<div class="card-list-wrapper" ref="cardWrapperRef">
|
||||||
|
<div class="card-list-inner" ref="cardListRef">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in loginList"
|
||||||
|
:key="index"
|
||||||
|
class="login-card"
|
||||||
|
@click="handleCardClick(item)"
|
||||||
|
>
|
||||||
|
<div class="icon-wrapper">
|
||||||
|
<img :src="item.icon" :alt="item.name" class="login-icon" />
|
||||||
|
</div>
|
||||||
|
<div class="card-name">{{ item.name }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-button
|
||||||
|
class="control-btn left-btn"
|
||||||
|
@click="scrollCards('left')"
|
||||||
|
:disabled="isLeftDisabled"
|
||||||
|
circle
|
||||||
|
size="mini"
|
||||||
|
icon="ArrowLeft"
|
||||||
|
></el-button>
|
||||||
|
<el-button
|
||||||
|
class="control-btn right-btn"
|
||||||
|
@click="scrollCards('right')"
|
||||||
|
:disabled="isRightDisabled"
|
||||||
|
circle
|
||||||
|
size="mini"
|
||||||
|
icon="ArrowRight"
|
||||||
|
></el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||||
|
import { ElButton, ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const loginList = ref([
|
||||||
|
{ icon: 'https://picsum.photos/120/80?1', name: '账号密码' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?2', name: '手机验证码' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?3', name: '微信登录' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?4', name: '支付宝登录' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?5', name: 'QQ登录' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?6', name: '微博登录' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?7', name: '邮箱登录' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?8', name: '抖音登录' },
|
||||||
|
{ icon: 'https://picsum.photos/120/80?9', name: '快手登录' }
|
||||||
|
])
|
||||||
|
|
||||||
|
const cardWrapperRef = ref(null)
|
||||||
|
const cardListRef = ref(null)
|
||||||
|
const scrollLeft = ref(0)
|
||||||
|
|
||||||
|
const isLeftDisabled = computed(() => {
|
||||||
|
return scrollLeft.value <= 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const isRightDisabled = computed(() => {
|
||||||
|
if (!cardWrapperRef.value || !cardListRef.value) return true
|
||||||
|
const maxScroll = cardListRef.value.scrollWidth - cardWrapperRef.value.clientWidth
|
||||||
|
return Math.round(scrollLeft.value) >= Math.round(maxScroll)
|
||||||
|
})
|
||||||
|
|
||||||
|
const scrollCards = (direction) => {
|
||||||
|
if (!cardListRef.value || !cardWrapperRef.value) return
|
||||||
|
const step = 128
|
||||||
|
const maxScroll = cardListRef.value.scrollWidth - cardWrapperRef.value.clientWidth
|
||||||
|
let newScroll = scrollLeft.value
|
||||||
|
|
||||||
|
if (direction === 'left') {
|
||||||
|
newScroll = Math.max(0, newScroll - step)
|
||||||
|
} else {
|
||||||
|
newScroll = Math.min(maxScroll, newScroll + step)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newScroll !== scrollLeft.value) {
|
||||||
|
cardListRef.value.scrollTo({
|
||||||
|
left: newScroll,
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
scrollLeft.value = newScroll
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCardClick = (item) => {
|
||||||
|
ElMessage.success(`选择了${item.name}登录`)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const list = cardListRef.value
|
||||||
|
if (list) {
|
||||||
|
scrollLeft.value = list.scrollLeft
|
||||||
|
list.addEventListener('scroll', () => {
|
||||||
|
scrollLeft.value = list.scrollLeft
|
||||||
|
})
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
if (cardListRef.value) {
|
||||||
|
scrollLeft.value = cardListRef.value.scrollLeft
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
const list = cardListRef.value
|
||||||
|
if (list) {
|
||||||
|
list.removeEventListener('scroll', () => {})
|
||||||
|
}
|
||||||
|
window.removeEventListener('resize', () => {})
|
||||||
|
})
|
||||||
|
|
||||||
|
watch([isLeftDisabled, isRightDisabled], () => {}, { immediate: true })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.quick-login-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
width: 100%;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-section {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
z-index: 100;
|
||||||
|
width: 16px !important;
|
||||||
|
height: 16px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
background-color: #e6f7ff !important;
|
||||||
|
border-color: #91d5ff !important;
|
||||||
|
color: #1890ff !important;
|
||||||
|
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: all 0.1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn:disabled {
|
||||||
|
background-color: #f0f8fb !important;
|
||||||
|
border-color: #b3d8ea !important;
|
||||||
|
color: #8cbfe8 !important;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn:not(:disabled):active {
|
||||||
|
background-color: #bae7ff !important;
|
||||||
|
border-color: #69c0ff !important;
|
||||||
|
color: #096dd9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-btn {
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-btn {
|
||||||
|
right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 16px);
|
||||||
|
padding: 8px 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-inner {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-inner::-webkit-scrollbar {
|
||||||
|
display: block;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-inner::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-inner::-webkit-scrollbar-thumb {
|
||||||
|
background: #dcdfe6;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-inner::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #c0c4cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-inner {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-card {
|
||||||
|
height: 100%;
|
||||||
|
width: 120px;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12);
|
||||||
|
background-color: #eff6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-icon {
|
||||||
|
width: 100%;
|
||||||
|
height: 80px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-name {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.4;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
152
screen-vue/src/views/desktop/components/UserTop.vue
Normal file
152
screen-vue/src/views/desktop/components/UserTop.vue
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
<template>
|
||||||
|
<div class="welcome-bar">
|
||||||
|
<div class="welcome-left">
|
||||||
|
<div class="avatar">
|
||||||
|
<img src="https://picsum.photos/48/48" alt="头像" />
|
||||||
|
</div>
|
||||||
|
<div class="welcome-text">
|
||||||
|
<div class="greeting">您好, 超级管理员, 开始您一天的工作吧!</div>
|
||||||
|
<div class="weather">今日小雪;夜间:多云;温度:(-4.0℃ 至 2.0℃);东北风/1-3级</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="welcome-right">
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">待办</div>
|
||||||
|
<div class="stat-value">0/0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">日程</div>
|
||||||
|
<div class="stat-value">0/0</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">项目</div>
|
||||||
|
<div class="stat-value">1/7</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-label">团队</div>
|
||||||
|
<div class="stat-value">6</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
userName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
weatherInfo: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.welcome-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.greeting {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式适配 - 适配主页面小屏幕布局 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.welcome-right {
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.greeting {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
313
screen-vue/src/views/myapp/web/list.vue
Normal file
313
screen-vue/src/views/myapp/web/list.vue
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
<template>
|
||||||
|
<div class="search-list-page">
|
||||||
|
<div class="search-section">
|
||||||
|
<div class="search-wrapper">
|
||||||
|
<el-input
|
||||||
|
v-model="searchForm.websiteName"
|
||||||
|
placeholder="请输入搜索网站名称"
|
||||||
|
class="search-input"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleSearch"
|
||||||
|
/>
|
||||||
|
<div class="search-btn-group">
|
||||||
|
<el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
|
||||||
|
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="list-wrapper">
|
||||||
|
<div class="list-section">
|
||||||
|
<div v-if="listData.length === 0" class="empty-tip">
|
||||||
|
<el-empty description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
<div v-else class="card-list">
|
||||||
|
<el-card
|
||||||
|
v-for="item in listData"
|
||||||
|
:key="item.websiteId"
|
||||||
|
class="list-card"
|
||||||
|
shadow="hover"
|
||||||
|
>
|
||||||
|
<div class="card-top">
|
||||||
|
<div class="site-main">
|
||||||
|
<el-tooltip :content="item.websiteName" placement="top">
|
||||||
|
<div class="site-name">{{ item.websiteName }}</div>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip :content="item.websiteUrl" placement="top">
|
||||||
|
<div class="site-url">{{ item.websiteUrl }}</div>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-divider"></div>
|
||||||
|
<div class="card-bottom">
|
||||||
|
<span class="card-date">{{ item.createTime }}</span>
|
||||||
|
<div class="card-actions">
|
||||||
|
<el-button size="small" type="primary" link @click="handleVisit(item)">
|
||||||
|
<el-icon><Link /></el-icon>
|
||||||
|
访问
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pagination-footer">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pagination.pageNum"
|
||||||
|
v-model:page-size="pagination.pageSize"
|
||||||
|
:page-sizes="[20, 50, 99]"
|
||||||
|
:total="pagination.total"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
background
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { Link } from '@element-plus/icons-vue'
|
||||||
|
import { getWebsiteStorageList } from '@/api/bizWebsiteStorage'
|
||||||
|
|
||||||
|
const searchForm = reactive({
|
||||||
|
websiteName: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const pagination = reactive({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const listData = ref([])
|
||||||
|
const getDataList = async () => {
|
||||||
|
try {
|
||||||
|
const reqParmas = {
|
||||||
|
...searchForm,
|
||||||
|
pageNum: pagination.pageNum,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
}
|
||||||
|
const res = await getWebsiteStorageList(reqParmas)
|
||||||
|
listData.value = res.list || []
|
||||||
|
pagination.total = res.total
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleVisit = (item) => {
|
||||||
|
window.open(item.websiteUrl, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.pageNum = 1
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
Object.assign(searchForm, {
|
||||||
|
websiteName: ''
|
||||||
|
})
|
||||||
|
pagination.pageNum = 1
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pagination.pageSize = val
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
pagination.pageNum = val
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getDataList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-list-page {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-section {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 0;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-section {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
padding: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-tip {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #f0f0f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08) !important;
|
||||||
|
border-color: #409eff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-top {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 6px 12px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #1f2937;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-url {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #9ca3af;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-url:hover {
|
||||||
|
color: #409eff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
margin: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-bottom {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-date {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-footer {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: #fff;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-section::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-section::-webkit-scrollbar-track {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-section::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-section::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.card-list {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
199
screen-vue/src/views/system/icon/index.vue
Normal file
199
screen-vue/src/views/system/icon/index.vue
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
<template>
|
||||||
|
<div class="icon-demo-container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="search-wrapper">
|
||||||
|
<el-input
|
||||||
|
v-model="searchKey"
|
||||||
|
placeholder="输入图标名称搜索"
|
||||||
|
class="search-input"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="search-icon"><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="icon-list-wrapper">
|
||||||
|
<div class="icon-list">
|
||||||
|
<div v-if="Object.keys(filteredIcons).length === 0" class="empty-tip">
|
||||||
|
未找到匹配的图标,请更换关键词重试
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="(icon, key) in filteredIcons"
|
||||||
|
:key="key"
|
||||||
|
class="icon-item"
|
||||||
|
@click="copyIconName(key)"
|
||||||
|
>
|
||||||
|
<div class="icon-wrapper">
|
||||||
|
<el-icon :size="32">
|
||||||
|
<component :is="key" />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="icon-name">{{ key }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||||
|
import { Search } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
const searchKey = ref('')
|
||||||
|
const filteredIcons = computed(() => {
|
||||||
|
if (!searchKey.value) {
|
||||||
|
return ElementPlusIconsVue
|
||||||
|
}
|
||||||
|
const lowerKey = searchKey.value.toLowerCase()
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(ElementPlusIconsVue).filter(([key]) =>
|
||||||
|
key.toLowerCase().includes(lowerKey)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const copyIconName = (key) => {
|
||||||
|
navigator.clipboard.writeText(key)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success(`已复制图标名称:${key}`)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage.error('复制失败,请手动复制')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.icon-demo-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 1px solid #e6e6e6;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h2 {
|
||||||
|
color: #333;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-list-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-tip {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-item:hover {
|
||||||
|
background: #e8eaed;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-wrapper {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #409eff;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-name {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
word-break: keep-all;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-list-wrapper::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
.icon-list-wrapper::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.icon-list-wrapper::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.icon-list-wrapper::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.icon-list {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
|
||||||
|
}
|
||||||
|
.header h2 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -60,7 +60,7 @@ public class HomeMenuController {
|
|||||||
}
|
}
|
||||||
allHomeMenus = allHomeMenus.stream()
|
allHomeMenus = allHomeMenus.stream()
|
||||||
.filter(menu -> targetIds.contains(menu.getMenuId()))
|
.filter(menu -> targetIds.contains(menu.getMenuId()))
|
||||||
.collect(Collectors.toList());
|
.toList();
|
||||||
}
|
}
|
||||||
Map<String, List<HomeMenu>> parentIdToChildrenMap = new HashMap<>();
|
Map<String, List<HomeMenu>> parentIdToChildrenMap = new HashMap<>();
|
||||||
for (HomeMenu menu : allHomeMenus) {
|
for (HomeMenu menu : allHomeMenus) {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.mini.mybigscreen.biz.controller;
|
||||||
|
|
||||||
|
import com.mini.mybigscreen.Model.Result;
|
||||||
|
import com.mini.mybigscreen.biz.service.HomeRoleService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表 前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/biz/homeRole")
|
||||||
|
public class HomeRoleController {
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private HomeRoleService roleService;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public Result<?> getList(){
|
||||||
|
return Result.success(roleService.list());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.mini.mybigscreen.biz.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色菜单表 前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/biz/homeRoleMenu")
|
||||||
|
public class HomeRoleMenuController {
|
||||||
|
|
||||||
|
}
|
||||||
44
src/main/java/com/mini/mybigscreen/biz/domain/HomeRole.java
Normal file
44
src/main/java/com/mini/mybigscreen/biz/domain/HomeRole.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package com.mini.mybigscreen.biz.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@TableName("biz_home_role")
|
||||||
|
public class HomeRole implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableField("create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@TableId(value = "role_id", type = IdType.AUTO)
|
||||||
|
private String roleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色名称
|
||||||
|
*/
|
||||||
|
@TableField("role_name")
|
||||||
|
private String roleName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
@TableField("ustatus")
|
||||||
|
private Integer ustatus;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.mini.mybigscreen.biz.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色菜单表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@TableName("biz_home_role_menu")
|
||||||
|
public class HomeRoleMenu implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableField("create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色编号
|
||||||
|
*/
|
||||||
|
@TableField("role_id")
|
||||||
|
private String roleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单编号
|
||||||
|
*/
|
||||||
|
@TableField("menu_id")
|
||||||
|
private String menuId;
|
||||||
|
|
||||||
|
@TableField("ustatus")
|
||||||
|
private Integer ustatus;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.mini.mybigscreen.biz.mapper;
|
||||||
|
|
||||||
|
import com.mini.mybigscreen.biz.domain.HomeRole;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
public interface HomeRoleMapper extends BaseMapper<HomeRole> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.mini.mybigscreen.biz.mapper;
|
||||||
|
|
||||||
|
import com.mini.mybigscreen.biz.domain.HomeRoleMenu;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色菜单表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
public interface HomeRoleMenuMapper extends BaseMapper<HomeRoleMenu> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.mini.mybigscreen.biz.service;
|
||||||
|
|
||||||
|
import com.mini.mybigscreen.biz.domain.HomeRoleMenu;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色菜单表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
public interface HomeRoleMenuService extends IService<HomeRoleMenu> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.mini.mybigscreen.biz.service;
|
||||||
|
|
||||||
|
import com.mini.mybigscreen.biz.domain.HomeRole;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
public interface HomeRoleService extends IService<HomeRole> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.mini.mybigscreen.biz.service.impl;
|
||||||
|
|
||||||
|
import com.mini.mybigscreen.biz.domain.HomeRoleMenu;
|
||||||
|
import com.mini.mybigscreen.biz.mapper.HomeRoleMenuMapper;
|
||||||
|
import com.mini.mybigscreen.biz.service.HomeRoleMenuService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色菜单表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class HomeRoleMenuServiceImpl extends ServiceImpl<HomeRoleMenuMapper, HomeRoleMenu> implements HomeRoleMenuService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.mini.mybigscreen.biz.service.impl;
|
||||||
|
|
||||||
|
import com.mini.mybigscreen.biz.domain.HomeRole;
|
||||||
|
import com.mini.mybigscreen.biz.mapper.HomeRoleMapper;
|
||||||
|
import com.mini.mybigscreen.biz.service.HomeRoleService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author gaoxq
|
||||||
|
* @since 2026-03-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class HomeRoleServiceImpl extends ServiceImpl<HomeRoleMapper, HomeRole> implements HomeRoleService {
|
||||||
|
|
||||||
|
}
|
||||||
18
src/main/resources/mapper/HomeRoleMapper.xml
Normal file
18
src/main/resources/mapper/HomeRoleMapper.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.mini.mybigscreen.biz.mapper.HomeRoleMapper">
|
||||||
|
|
||||||
|
<!-- 通用查询映射结果 -->
|
||||||
|
<resultMap id="BaseResultMap" type="com.mini.mybigscreen.biz.domain.HomeRole">
|
||||||
|
<id column="role_id" property="roleId" />
|
||||||
|
<result column="create_time" property="createTime" />
|
||||||
|
<result column="role_name" property="roleName" />
|
||||||
|
<result column="ustatus" property="ustatus" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- 通用查询结果列 -->
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
create_time, role_id, role_name, ustatus
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
19
src/main/resources/mapper/HomeRoleMenuMapper.xml
Normal file
19
src/main/resources/mapper/HomeRoleMenuMapper.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.mini.mybigscreen.biz.mapper.HomeRoleMenuMapper">
|
||||||
|
|
||||||
|
<!-- 通用查询映射结果 -->
|
||||||
|
<resultMap id="BaseResultMap" type="com.mini.mybigscreen.biz.domain.HomeRoleMenu">
|
||||||
|
<id column="id" property="id" />
|
||||||
|
<result column="create_time" property="createTime" />
|
||||||
|
<result column="role_id" property="roleId" />
|
||||||
|
<result column="menu_id" property="menuId" />
|
||||||
|
<result column="ustatus" property="ustatus" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- 通用查询结果列 -->
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
create_time, id, role_id, menu_id, ustatus
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user