Files
sifa-admin/src/views/dashboard/workplace/index.vue
T
南宁网宿科技 13bed2bafb Initial commit
2023-06-03 23:57:39 +08:00

303 lines
6.9 KiB
Vue

<template>
<div class="ele-body ele-body-card">
<profile-card />
<link-card ref="linkCardRef" />
<a-row :gutter="16" ref="wrapRef">
<a-col
v-for="(item, index) in data"
:key="item.name"
:lg="item.lg"
:md="item.md"
:sm="item.sm"
:xs="item.xs"
>
<component
:is="item.name"
:title="item.title"
@remove="onRemove(index)"
@edit="onEdit(index)"
/>
</a-col>
</a-row>
<a-card :bordered="false" :body-style="{ padding: 0 }">
<div class="ele-cell" style="line-height: 42px">
<div
class="ele-cell-content ele-text-primary workplace-bottom-btn"
@click="add"
>
<PlusCircleOutlined /> 添加视图
</div>
<a-divider type="vertical" />
<div
class="ele-cell-content ele-text-primary workplace-bottom-btn"
@click="reset"
>
<UndoOutlined /> 重置布局
</div>
</div>
</a-card>
<ele-modal
:width="680"
v-model:visible="visible"
title="未添加的视图"
:footer="null"
>
<a-row :gutter="16">
<a-col
v-for="item in notAddedData"
:key="item.name"
:md="8"
:sm="12"
:xs="24"
>
<div
class="workplace-card-item ele-border-split"
@click="addView(item)"
>
<div class="workplace-card-header ele-border-split">
{{ item.title }}
</div>
<div class="workplace-card-body ele-text-placeholder">
<plus-circle-outlined />
</div>
</div>
</a-col>
</a-row>
<a-empty v-if="!notAddedData.length" description="已添加所有视图" />
</ele-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import SortableJs from 'sortablejs';
import type { Row as ARow } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import { PlusCircleOutlined, UndoOutlined } from '@ant-design/icons-vue';
import ProfileCard from './components/profile-card.vue';
import LinkCard from './components/link-card.vue';
const CACHE_KEY = 'workplace-layout';
interface ViewItem {
name: string;
title: string;
lg: number;
md: number;
sm: number;
xs: number;
}
// 默认布局
const DEFAULT: ViewItem[] = [
// {
// name: 'project-card',
// title: '项目管理',
// lg: 16,
// md: 24,
// sm: 24,
// xs: 24
// },
// {
// name: 'user-list',
// title: '小组成员',
// lg: 8,
// md: 24,
// sm: 24,
// xs: 24
// },
// {
// name: 'activities-card',
// title: '最新动态',
// lg: 8,
// md: 24,
// sm: 24,
// xs: 24
// },
// {
// name: 'task-card',
// title: '我的任务',
// lg: 8,
// md: 24,
// sm: 24,
// xs: 24
// },
// {
// name: 'goal-card',
// title: '本月目标',
// lg: 8,
// md: 24,
// sm: 24,
// xs: 24
// },
// {
// name: 'docs',
// title: '知识库',
// lg: 8,
// md: 24,
// sm: 24,
// xs: 24
// }
];
// 获取缓存的顺序
const cache = (() => {
const str = localStorage.getItem(CACHE_KEY);
try {
return str ? JSON.parse(str) : null;
} catch (e) {
return null;
}
})();
const data = ref<ViewItem[]>([...(cache ?? DEFAULT)]);
const visible = ref(false);
const linkCardRef = ref<InstanceType<typeof LinkCard> | null>(null);
const wrapRef = ref<InstanceType<typeof ARow> | null>(null);
let sortableIns: SortableJs | null = null;
// 未添加的数据
const notAddedData = computed(() => {
return DEFAULT.filter((d) => !data.value.some((t) => t.name === d.name));
});
/* 添加 */
const add = () => {
visible.value = true;
};
/* 重置布局 */
const reset = () => {
data.value = [...DEFAULT];
cacheData();
linkCardRef.value?.reset();
message.success('已重置');
};
/* 缓存布局 */
const cacheData = () => {
localStorage.setItem(CACHE_KEY, JSON.stringify(data.value));
};
/* 删除视图 */
const onRemove = (index: number) => {
data.value = data.value.filter((_d, i) => i !== index);
cacheData();
};
/* 编辑视图 */
const onEdit = (index: number) => {
data.value.map((d) => {
if (d.name == 'user-list') {
}
});
// message.info('点击了编辑');
};
/* 添加视图 */
const addView = (item) => {
data.value.push(item);
cacheData();
message.success('已添加');
};
onMounted(() => {
const isTouchDevice = 'ontouchstart' in document.documentElement;
if (isTouchDevice) {
return;
}
sortableIns = new SortableJs(wrapRef.value?.$el, {
handle: '.ant-card-head',
animation: 300,
onUpdate: ({ oldIndex, newIndex }) => {
if (typeof oldIndex === 'number' && typeof newIndex === 'number') {
const temp = [...data.value];
temp.splice(newIndex, 0, temp.splice(oldIndex, 1)[0]);
data.value = temp;
cacheData();
}
},
setData: () => {}
});
});
onBeforeUnmount(() => {
if (sortableIns) {
sortableIns.destroy();
}
});
</script>
<script lang="ts">
import ActivitiesCard from './components/activities-card.vue';
import TaskCard from './components/task-card.vue';
import GoalCard from './components/goal-card.vue';
import ProjectCard from './components/project-card.vue';
import UserList from './components/user-list.vue';
import Docs from './components/docs.vue';
export default {
name: 'DashboardWorkplace',
components: {
ProjectCard,
UserList,
ActivitiesCard,
TaskCard,
GoalCard,
Docs
}
};
</script>
<style lang="less" scoped>
.ele-body :deep(.ant-card-head) {
cursor: move;
position: relative;
}
.ele-body :deep(.ant-row > .ant-col.sortable-chosen > .ant-card) {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
}
.workplace-bottom-btn {
text-align: center;
cursor: pointer;
transition: background-color 0.2s;
}
.workplace-bottom-btn:hover {
background: hsla(0, 0%, 60%, 0.05);
}
/* 添加弹窗 */
.workplace-card-item {
margin-bottom: 15px;
border-width: 1px;
border-style: solid;
border-radius: 4px;
position: relative;
cursor: pointer;
transition: box-shadow 0.2s, background-color 0.2s;
}
.workplace-card-item:hover {
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.1);
background: hsla(0, 0%, 60%, 0.05);
}
.workplace-card-item .workplace-card-header {
border-bottom-width: 1px;
border-bottom-style: solid;
padding: 8px;
}
.workplace-card-body {
font-size: 26px;
padding: 24px 10px;
text-align: center;
}
</style>