mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-14 21:02:49 +00:00
feat: 首页改版
This commit is contained in:
parent
ecdbf8765f
commit
32aae08ef2
@ -81,6 +81,7 @@ class ProjectTaskContent extends AbstractModel
|
||||
Base::makeDir(dirname($publicPath));
|
||||
$result = file_put_contents($publicPath, $content);
|
||||
if(!$result){
|
||||
// todo 记录失败日志便于追查具体原因
|
||||
info("保存任务详情至文件失败");
|
||||
info($publicPath);
|
||||
info($oldContent);
|
||||
|
||||
@ -1401,3 +1401,5 @@ APP推送
|
||||
必须大于0
|
||||
忍心拒绝
|
||||
请等待打包完成
|
||||
选择一个项目查看更多任务
|
||||
首页
|
||||
|
||||
@ -17834,7 +17834,7 @@
|
||||
"key": "应用",
|
||||
"zh": "",
|
||||
"zh-CHT": "應用",
|
||||
"en": "Application",
|
||||
"en": "Apps",
|
||||
"ko": "응용",
|
||||
"ja": "応用です",
|
||||
"de": "Anwendung",
|
||||
@ -18478,5 +18478,38 @@
|
||||
"de": "Ich kann das einfach nicht.",
|
||||
"fr": "Tolérance et refus",
|
||||
"id": "Punya hati untuk menolak"
|
||||
},
|
||||
{
|
||||
"key": "请等待打包完成",
|
||||
"zh": "",
|
||||
"zh-CHT": "請等待打包完成",
|
||||
"en": "Please wait for packing to complete",
|
||||
"ko": "패키지가 끝날 때까지 기다려 주세요",
|
||||
"ja": "梱包が完了するまでお待ちいただけます。",
|
||||
"de": "Bitte warten sie, bis ihr koffer fertig ist",
|
||||
"fr": "Veuillez attendre que l’emballage soit terminé",
|
||||
"id": "Tunggu sampai paket selesai"
|
||||
},
|
||||
{
|
||||
"key": "选择一个项目查看更多任务",
|
||||
"zh": "",
|
||||
"zh-CHT": "選擇一個項目查看更多任務",
|
||||
"en": "Select a project to view more tasks",
|
||||
"ko": "더 많은 작업을 보려면 항목을 선택하십시오",
|
||||
"ja": "1つのプロジェクトを選んでより多くのタスクを見ます",
|
||||
"de": "Wählen sie ein projekt, um weitere aufgaben wahrzunehmen",
|
||||
"fr": "Sélectionnez un projet pour voir plus de tâches",
|
||||
"id": "Pilih satu item untuk melihat lebih banyak tugas"
|
||||
},
|
||||
{
|
||||
"key": "首页",
|
||||
"zh": "",
|
||||
"zh-CHT": "首頁",
|
||||
"en": "Home",
|
||||
"ko": "첫 페이지",
|
||||
"ja": "トップページです",
|
||||
"de": "Die titelseite.",
|
||||
"fr": "La page de couverture",
|
||||
"id": "Halaman depan"
|
||||
}
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
public/images/empty/empty.svg
Normal file
1
public/images/empty/empty.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
2
public/language/web/de.js
vendored
2
public/language/web/de.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/en.js
vendored
2
public/language/web/en.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/fr.js
vendored
2
public/language/web/fr.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/id.js
vendored
2
public/language/web/id.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/ja.js
vendored
2
public/language/web/ja.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/key.js
vendored
2
public/language/web/key.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/ko.js
vendored
2
public/language/web/ko.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/zh-CHT.js
vendored
2
public/language/web/zh-CHT.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/zh.js
vendored
2
public/language/web/zh.js
vendored
@ -1 +1 @@
|
||||
if(typeof window.LANGUAGE_DATA==="undefined")window.LANGUAGE_DATA={};window.LANGUAGE_DATA["zh"]=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]
|
||||
if(typeof window.LANGUAGE_DATA==="undefined")window.LANGUAGE_DATA={};window.LANGUAGE_DATA["zh"]=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]
|
||||
@ -5,17 +5,13 @@
|
||||
class="page-manage-menu-dropdown main-menu"
|
||||
trigger="click"
|
||||
@on-click="settingRoute"
|
||||
@on-visible-change="menuVisibleChange">
|
||||
@on-visible-change="menuVisibleChange"
|
||||
transfer>
|
||||
<div :class="['manage-box-title', visibleMenu ? 'menu-visible' : '']">
|
||||
<div class="manage-box-avatar">
|
||||
<UserAvatar :userid="userId" :size="36" tooltipDisabled/>
|
||||
<UserAvatar :userid="userId" :size="48" tooltipDisabled/>
|
||||
</div>
|
||||
<span>{{userInfo.nickname}}</span>
|
||||
<Badge v-if="!!clientNewVersion" class="manage-box-top-report" dot/>
|
||||
<div class="manage-box-arrow">
|
||||
<Icon type="ios-arrow-up" />
|
||||
<Icon type="ios-arrow-down" />
|
||||
</div>
|
||||
</div>
|
||||
<DropdownMenu slot="list">
|
||||
<template v-for="item in menu">
|
||||
@ -96,21 +92,24 @@
|
||||
<div class="menu-base">
|
||||
<ul>
|
||||
<li @click="toggleRoute('dashboard')" :class="classNameRoute('dashboard')">
|
||||
<i class="taskfont"></i>
|
||||
<div class="menu-title">{{$L('仪表盘')}}</div>
|
||||
<i class="taskfont" v-if="!classNameRoute('dashboard')?.active"></i>
|
||||
<i class="taskfont" v-else></i>
|
||||
<div class="menu-title">{{$L('首页')}}</div>
|
||||
<Badge v-if="dashboardTask.overdue_count > 0" class="menu-badge" type="error" :overflow-count="999" :count="dashboardTask.overdue_count"/>
|
||||
<Badge v-else-if="dashboardTask.today_count > 0" class="menu-badge" type="info" :overflow-count="999" :count="dashboardTask.today_count"/>
|
||||
<Badge v-else-if="dashboardTask.all_count > 0" class="menu-badge" type="primary" :overflow-count="999" :count="dashboardTask.all_count"/>
|
||||
</li>
|
||||
<li @click="toggleRoute('calendar')" :class="classNameRoute('calendar')">
|
||||
<i class="taskfont"></i>
|
||||
<div class="menu-title">{{$L('日历')}}</div>
|
||||
</li>
|
||||
<li @click="toggleRoute('messenger')" :class="classNameRoute('messenger')">
|
||||
<i class="taskfont"></i>
|
||||
<i class="taskfont" v-if="!classNameRoute('messenger')?.active"></i>
|
||||
<i class="taskfont" v-else></i>
|
||||
<div class="menu-title">{{$L('消息')}}</div>
|
||||
<Badge class="menu-badge" :overflow-count="999" :text="msgUnreadMention"/>
|
||||
</li>
|
||||
<li @click="toggleRoute('project')" :class="classNameRoute('project')">
|
||||
<i class="taskfont" v-if="!classNameRoute('project')?.active"></i>
|
||||
<i class="taskfont" v-else></i>
|
||||
<div class="menu-title">{{$L('项目')}}</div>
|
||||
</li>
|
||||
<li @click="toggleRoute('file')" :class="classNameRoute('file')">
|
||||
<i class="taskfont"></i>
|
||||
<div class="menu-title">{{$L('文件')}}</div>
|
||||
@ -122,77 +121,31 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div ref="menuProject" class="menu-project">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(item, key) in projectLists"
|
||||
:ref="`project_${item.id}`"
|
||||
:key="key"
|
||||
:class="classNameProject(item)"
|
||||
:data-id="item.id"
|
||||
@click="toggleRoute('project', {projectId: item.id})"
|
||||
v-longpress="handleLongpress">
|
||||
<div class="project-h1">
|
||||
<em @click.stop="toggleOpenMenu(item.id)"></em>
|
||||
<div class="title">{{item.name}}</div>
|
||||
<div v-if="item.top_at" class="icon-top"></div>
|
||||
<div v-if="item.task_my_num - item.task_my_complete > 0" class="num">{{item.task_my_num - item.task_my_complete}}</div>
|
||||
</div>
|
||||
<div class="project-h2">
|
||||
<p>
|
||||
<em>{{$L('我的')}}:</em>
|
||||
<span>{{item.task_my_complete}}/{{item.task_my_num}}</span>
|
||||
<Progress :percent="item.task_my_percent" :stroke-width="6" />
|
||||
</p>
|
||||
<p>
|
||||
<em>{{$L('全部')}}:</em>
|
||||
<span>{{item.task_complete}}/{{item.task_num}}</span>
|
||||
<Progress :percent="item.task_percent" :stroke-width="6" />
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="projectKeyLoading > 0" class="loading"><Loading/></li>
|
||||
</ul>
|
||||
</div>
|
||||
</Scrollbar>
|
||||
<div class="operate-position" :style="operateStyles" v-show="operateVisible">
|
||||
<Dropdown
|
||||
trigger="custom"
|
||||
:placement="windowLandscape ? 'bottom' : 'top'"
|
||||
:visible="operateVisible"
|
||||
@on-clickoutside="operateVisible = false"
|
||||
transfer>
|
||||
<div :style="{userSelect:operateVisible ? 'none' : 'auto', height: operateStyles.height}"></div>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem @click.native="handleTopClick">
|
||||
{{ $L(operateItem.top_at ? '取消置顶' : '置顶该项目') }}
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
<div class="manage-box-new-group">
|
||||
<ul>
|
||||
<li>
|
||||
<Tooltip :content="$L('新建项目') + ' ('+mateName+'+B)'" placement="top-start" transfer :delay="300">
|
||||
<i class="taskfont" @click="onAddShow"></i>
|
||||
</Tooltip>
|
||||
</li>
|
||||
<li>
|
||||
<Tooltip :content="$L('新建任务') + ' ('+mateName+'+K)'" placement="top-start" transfer :delay="300">
|
||||
<i class="taskfont" @click="onAddMenu('task')"></i>
|
||||
</Tooltip>
|
||||
</li>
|
||||
<li>
|
||||
<Tooltip :content="$L('新会议') + ' ('+mateName+'+J)'" placement="top-start" transfer :delay="300">
|
||||
<i class="taskfont" @click="onAddMenu('createMeeting')"></i>
|
||||
</Tooltip>
|
||||
</li>
|
||||
<li>
|
||||
<Tooltip :content="$L('加入会议')" placement="top-start" transfer :delay="300">
|
||||
<i class="taskfont" @click="onAddMenu('joinMeeting')"></i>
|
||||
</Tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-if="(projectSearchShow || projectTotal > 20) && windowHeight > 600"
|
||||
class="manage-project-search">
|
||||
<Input v-model="projectKeyValue" :placeholder="$L(`共${projectTotal || cacheProjects.length}个项目,搜索...`)" clearable>
|
||||
<div class="search-pre" slot="prefix">
|
||||
<Loading v-if="projectKeyLoading > 0"/>
|
||||
<Icon v-else type="ios-search" />
|
||||
</div>
|
||||
</Input>
|
||||
</div>
|
||||
<ButtonGroup class="manage-box-new-group">
|
||||
<Button class="manage-box-new" type="primary" icon="md-add" @click="onAddShow">{{$L('新建项目')}}</Button>
|
||||
<Dropdown @on-click="onAddMenu" trigger="click">
|
||||
<Button type="primary">
|
||||
<Icon type="ios-arrow-down"></Icon>
|
||||
</Button>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem name="task">{{$L('新建任务')}} ({{mateName}}+K)</DropdownItem>
|
||||
<DropdownItem name="createMeeting">{{$L('新会议')}} ({{mateName}}+J)</DropdownItem>
|
||||
<DropdownItem name="joinMeeting">{{$L('加入会议')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
|
||||
<div class="manage-box-main">
|
||||
@ -373,14 +326,8 @@ export default {
|
||||
exportCheckinShow: false,
|
||||
exportApproveShow: false,
|
||||
|
||||
|
||||
dialogMsgSubscribe: null,
|
||||
|
||||
projectKeyValue: '',
|
||||
projectKeyLoading: 0,
|
||||
projectSearchShow: false,
|
||||
|
||||
openMenu: {},
|
||||
visibleMenu: false,
|
||||
showMobileMenu: false,
|
||||
|
||||
@ -394,10 +341,6 @@ export default {
|
||||
|
||||
reportTabs: "my",
|
||||
|
||||
operateStyles: {},
|
||||
operateVisible: false,
|
||||
operateItem: {},
|
||||
|
||||
needStartHome: false,
|
||||
}
|
||||
},
|
||||
@ -448,8 +391,6 @@ export default {
|
||||
'cacheUserBasic',
|
||||
'cacheTasks',
|
||||
'cacheDialogs',
|
||||
'cacheProjects',
|
||||
'projectTotal',
|
||||
'wsOpenNum',
|
||||
'columnTemplate',
|
||||
|
||||
@ -608,19 +549,6 @@ export default {
|
||||
return array
|
||||
},
|
||||
|
||||
projectLists() {
|
||||
const {projectKeyValue, cacheProjects} = this;
|
||||
const data = $A.cloneJSON(cacheProjects).sort((a, b) => {
|
||||
if (a.top_at || b.top_at) {
|
||||
return $A.Date(b.top_at) - $A.Date(a.top_at);
|
||||
}
|
||||
return b.id - a.id;
|
||||
});
|
||||
if (projectKeyValue) {
|
||||
return data.filter(item => $A.strExists(`${item.name} ${item.desc}`, projectKeyValue));
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
taskBrowseLists() {
|
||||
const {cacheTasks, cacheTaskBrowse, userId} = this;
|
||||
@ -646,17 +574,6 @@ export default {
|
||||
this.chackPass();
|
||||
},
|
||||
|
||||
projectKeyValue(val) {
|
||||
if (val == '') {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (this.projectKeyValue == val) {
|
||||
this.searchProject();
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
|
||||
wsOpenNum(num) {
|
||||
if (num <= 1) return
|
||||
this.$store.dispatch("getBasicData", 600)
|
||||
@ -668,25 +585,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
'cacheProjects.length': {
|
||||
handler() {
|
||||
this.$nextTick(_ => {
|
||||
const menuProject = this.$refs.menuProject
|
||||
const lastEl = $A.last($A.getObject(menuProject, 'children.0.children'))
|
||||
if (lastEl) {
|
||||
const lastRect = lastEl.getBoundingClientRect()
|
||||
const menuRect = menuProject.getBoundingClientRect()
|
||||
if (lastRect.top > menuRect.top + menuRect.height) {
|
||||
this.projectSearchShow = true
|
||||
return
|
||||
}
|
||||
}
|
||||
this.projectSearchShow = false
|
||||
})
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
|
||||
unreadAndOverdue: {
|
||||
handler(val) {
|
||||
if (this.$Electron) {
|
||||
@ -733,10 +631,6 @@ export default {
|
||||
this.goForward(location);
|
||||
},
|
||||
|
||||
toggleOpenMenu(id) {
|
||||
this.$set(this.openMenu, id, !this.openMenu[id])
|
||||
},
|
||||
|
||||
settingRoute(path) {
|
||||
switch (path) {
|
||||
case 'allUser':
|
||||
@ -786,8 +680,8 @@ export default {
|
||||
return;
|
||||
case 'okrManage':
|
||||
case 'okrAnalyze':
|
||||
this.goForward({
|
||||
path:'/manage/apps/' + ( path == 'okrManage' ? '/#/list' : '/#/analysis'),
|
||||
this.goForward({
|
||||
path:'/manage/apps/' + ( path == 'okrManage' ? '/#/list' : '/#/analysis'),
|
||||
});
|
||||
return;
|
||||
case 'logout':
|
||||
@ -833,7 +727,7 @@ export default {
|
||||
|
||||
classNameRoute(path) {
|
||||
let routeName = this.routeName
|
||||
if(routeName == 'manage-approve' || routeName == 'manage-apps'){
|
||||
if(routeName == 'manage-approve' || routeName == 'manage-apps' || routeName == 'manage-calendar'){
|
||||
routeName = `manage-application`
|
||||
}
|
||||
return {
|
||||
@ -841,14 +735,6 @@ export default {
|
||||
};
|
||||
},
|
||||
|
||||
classNameProject(item) {
|
||||
return {
|
||||
"active": this.routeName === 'manage-project' && this.$route.params.projectId == item.id,
|
||||
"open-menu": this.openMenu[item.id] === true,
|
||||
"operate": item.id == this.operateItem.id && this.operateVisible
|
||||
};
|
||||
},
|
||||
|
||||
onAddMenu(name) {
|
||||
switch (name) {
|
||||
case 'task':
|
||||
@ -900,18 +786,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
searchProject() {
|
||||
setTimeout(() => {
|
||||
this.projectKeyLoading++;
|
||||
}, 1000)
|
||||
this.$store.dispatch("getProjects", {
|
||||
keys: {
|
||||
name: this.projectKeyValue
|
||||
}
|
||||
}).finally(_ => {
|
||||
this.projectKeyLoading--;
|
||||
});
|
||||
},
|
||||
|
||||
selectChange(index) {
|
||||
this.$nextTick(() => {
|
||||
@ -1063,45 +937,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
handleLongpress(event, el) {
|
||||
const projectId = $A.getAttr(el, 'data-id')
|
||||
const projectItem = this.projectLists.find(item => item.id == projectId)
|
||||
if (!projectItem) {
|
||||
return
|
||||
}
|
||||
this.operateVisible = false;
|
||||
this.operateItem = $A.isJson(projectItem) ? projectItem : {};
|
||||
this.$nextTick(() => {
|
||||
const projectRect = el.getBoundingClientRect();
|
||||
const wrapRect = this.$refs.menuProject.getBoundingClientRect();
|
||||
this.operateStyles = {
|
||||
left: `${event.clientX - wrapRect.left}px`,
|
||||
top: `${projectRect.top + this.windowScrollY}px`,
|
||||
height: projectRect.height + 'px',
|
||||
}
|
||||
this.operateVisible = true;
|
||||
})
|
||||
},
|
||||
|
||||
handleTopClick() {
|
||||
this.$store.dispatch("call", {
|
||||
url: 'project/top',
|
||||
data: {
|
||||
project_id: this.operateItem.id,
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.$store.dispatch("saveProject", data);
|
||||
this.$nextTick(() => {
|
||||
const active = this.$refs.menuProject.querySelector(".active")
|
||||
if (active) {
|
||||
$A.scrollIntoViewIfNeeded(active);
|
||||
}
|
||||
});
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
});
|
||||
},
|
||||
|
||||
onTabbarClick(act) {
|
||||
switch (act) {
|
||||
case 'addTask':
|
||||
|
||||
@ -309,7 +309,8 @@ export default {
|
||||
{ value: "okr", label: "OKR管理" },
|
||||
{ value: "robot", label: "AI机器人" },
|
||||
{ value: "signin", label: "签到" },
|
||||
{ value: "meeting", label: "会议" }
|
||||
{ value: "meeting", label: "会议" },
|
||||
{ value: "calendar", label: "日历" },
|
||||
];
|
||||
// wap模式
|
||||
let appApplyList = this.windowOrientation != 'portrait' ? (
|
||||
@ -317,7 +318,6 @@ export default {
|
||||
{ value: "scan", label: "扫一扫" }
|
||||
] : []
|
||||
) : [
|
||||
{ value: "calendar", label: "日历" },
|
||||
{ value: "file", label: "文件" },
|
||||
{ value: "addProject", label: "创建项目" },
|
||||
{ value: "addTask", label: "添加任务" },
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<div class="calendar-head">
|
||||
<div class="calendar-titbox">
|
||||
<div class="calendar-title">
|
||||
<div class="common-nav-back portrait" @click="goForward({name: 'manage-application'},true)"><i class="taskfont"></i></div>
|
||||
<div class="common-nav-back" @click="goForward({name: 'manage-application'},true)"><i class="taskfont"></i></div>
|
||||
<h1>{{rangeText}}</h1>
|
||||
</div>
|
||||
<ButtonGroup class="calendar-arrow" size="small">
|
||||
|
||||
@ -151,25 +151,28 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.view)
|
||||
console.log(this.calendars)
|
||||
this.calendarInstance = new Calendar(this.$refs.tuiCalendar, {
|
||||
defaultView: this.view,
|
||||
taskView: this.taskView,
|
||||
scheduleView: this.scheduleView,
|
||||
theme: this.theme,
|
||||
template: this.template,
|
||||
week: this.week,
|
||||
month: this.month,
|
||||
calendars: this.calendars,
|
||||
useCreationPopup: this.useCreationPopup,
|
||||
useDetailPopup: this.useDetailPopup,
|
||||
timezones: this.timezones,
|
||||
disableDblClick: this.disableDblClick,
|
||||
disableClick: this.disableClick,
|
||||
isReadOnly: this.isReadOnly,
|
||||
usageStatistics: this.usageStatistics
|
||||
calendars: [],
|
||||
// taskView: this.taskView,
|
||||
// scheduleView: this.scheduleView,
|
||||
// theme: this.theme,
|
||||
// template: this.template,
|
||||
// week: this.week,
|
||||
// month: this.month,
|
||||
// calendars: this.calendars,
|
||||
// useCreationPopup: this.useCreationPopup,
|
||||
// useDetailPopup: this.useDetailPopup,
|
||||
// timezones: this.timezones,
|
||||
// disableDblClick: this.disableDblClick,
|
||||
// disableClick: this.disableClick,
|
||||
// isReadOnly: this.isReadOnly,
|
||||
// usageStatistics: this.usageStatistics
|
||||
});
|
||||
this.addEventListeners();
|
||||
this.reflectSchedules();
|
||||
// this.addEventListeners();
|
||||
// this.reflectSchedules();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.calendarInstance.off();
|
||||
|
||||
454
resources/assets/js/pages/manage/components/HomeCalendar.vue
Normal file
454
resources/assets/js/pages/manage/components/HomeCalendar.vue
Normal file
@ -0,0 +1,454 @@
|
||||
<template>
|
||||
<div class="home-calendar">
|
||||
<div class="calendar-header">
|
||||
<div class="calendar-header-menu">
|
||||
<h4>{{$L('(*).(*)', year, month)}}</h4>
|
||||
</div>
|
||||
<ButtonGroup size="small" >
|
||||
<Button><Icon type="ios-arrow-back" class="month-less" @click="prevMonth"/></Button>
|
||||
<Button><Icon type="ios-arrow-forward" class="month-add" @click="nextMonth"/></Button>
|
||||
</ButtonGroup>
|
||||
<Button class="calendar-header-back" size="small" @click="nowMonth">{{$L('今天')}}</Button>
|
||||
</div>
|
||||
<Scrollbar class="calendar-content">
|
||||
<div class="calendar-content" @scroll="handleScroll">
|
||||
<transition name="slide-up">
|
||||
<table class="calendar-table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{$L('日')}}</th>
|
||||
<th>{{$L('一')}}</th>
|
||||
<th>{{$L('二')}}</th>
|
||||
<th>{{$L('三')}}</th>
|
||||
<th>{{$L('四')}}</th>
|
||||
<th>{{$L('五')}}</th>
|
||||
<th>{{$L('六')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in dateArray">
|
||||
<template v-for="data in item">
|
||||
<td v-if="data.month" :class="{today: data.today}">
|
||||
<ETooltip max-width="auto" :disabled="true">
|
||||
<div slot="content" v-html="getTimes(data.date)"></div>
|
||||
<div @click="onDayClick(data)" class="item-day">
|
||||
<div>{{data.day}}</div>
|
||||
<i v-if="isCheck(data)" class="badge"></i>
|
||||
</div>
|
||||
</ETooltip>
|
||||
</td>
|
||||
<td v-else class="disabled">
|
||||
<div @click="onDayClick(data)" class="item-day">
|
||||
<div>{{data.day}}</div>
|
||||
</div>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</transition>
|
||||
<div v-if="loadIng" class="calendar-loading">
|
||||
<Loading/>
|
||||
</div>
|
||||
<!-- -->
|
||||
<div class="calendar-tui">
|
||||
<div style="height: 250px;">
|
||||
<Calendar
|
||||
ref="cal"
|
||||
:view="calendarView"
|
||||
:theme="calendarTheme"
|
||||
:template="calendarTemplate"
|
||||
:schedules="list"
|
||||
:taskView="false"
|
||||
:useCreationPopup="false"
|
||||
@beforeCreateSchedule="onBeforeCreateSchedule"
|
||||
@beforeClickSchedule="onBeforeClickSchedule"
|
||||
@beforeUpdateSchedule="onBeforeUpdateSchedule"
|
||||
disable-click/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import 'tui-date-picker/dist/tui-date-picker.css';
|
||||
import 'tui-time-picker/dist/tui-time-picker.css';
|
||||
import 'tui-calendar-hi/dist/tui-calendar-hi.css'
|
||||
|
||||
import {mapState, mapGetters} from "vuex";
|
||||
import Calendar from "./Calendar";
|
||||
import {Store} from "le5le-store";
|
||||
import TaskMenu from "./TaskMenu";
|
||||
import {addLanguage} from "../../../language";
|
||||
|
||||
export default {
|
||||
name: 'HomeCalendar',
|
||||
components: {TaskMenu, Calendar},
|
||||
props: {
|
||||
checkin: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
//
|
||||
year: '',
|
||||
month: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
dateArray: [],
|
||||
historys: [],
|
||||
showTable: true,
|
||||
//
|
||||
lists: [],
|
||||
rangeText: 'Calendar',
|
||||
rangeTime: [],
|
||||
calendarView: 'day',
|
||||
calendarWeek: {},
|
||||
calendarMonth: {},
|
||||
calendarTheme: {},
|
||||
calendarTemplate: {},
|
||||
calendarTask: {},
|
||||
calendarMenuStyles: {
|
||||
top: 0,
|
||||
left: 0
|
||||
},
|
||||
loadTimeout: null,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
const today = new Date()
|
||||
this.year = today.getFullYear();
|
||||
this.month = today.getMonth() + 1;
|
||||
this.generateCalendar();
|
||||
this.generateCalendarInstance();
|
||||
},
|
||||
computed: {
|
||||
...mapState(['cacheTasks', 'taskCompleteTemps', 'wsOpenNum', 'themeIsDark']),
|
||||
|
||||
...mapGetters(['transforTasks']),
|
||||
|
||||
list() {
|
||||
const {cacheTasks, taskCompleteTemps} = this;
|
||||
const filterTask = (task, chackCompleted = true) => {
|
||||
if (task.archived_at) {
|
||||
return false;
|
||||
}
|
||||
if (task.complete_at && chackCompleted === true) {
|
||||
return false;
|
||||
}
|
||||
if (!task.end_at) {
|
||||
return false;
|
||||
}
|
||||
return task.owner == 1;
|
||||
}
|
||||
let array = cacheTasks.filter(task => filterTask(task));
|
||||
if (taskCompleteTemps.length > 0) {
|
||||
let tmps = cacheTasks.filter(task => taskCompleteTemps.includes(task.id) && filterTask(task, false));
|
||||
if (tmps.length > 0) {
|
||||
array = $A.cloneJSON(array)
|
||||
array.push(...tmps);
|
||||
}
|
||||
}
|
||||
return this.transforTasks(array).map(data => {
|
||||
const isAllday = $A.rightExists(data.start_at, "00:00:00") && $A.rightExists(data.end_at, "23:59:59")
|
||||
const task = {
|
||||
id: data.id,
|
||||
calendarId: String(data.project_id),
|
||||
title: data.name,
|
||||
body: data.desc,
|
||||
isAllDay: isAllday,
|
||||
category: isAllday ? 'allday' : 'time',
|
||||
start: $A.Date(data.start_at).toISOString(),
|
||||
end: $A.Date(data.end_at).toISOString(),
|
||||
color: "#515a6e",
|
||||
bgColor: data.color || '#E3EAFD',
|
||||
borderColor: data.p_color,
|
||||
priority: '',
|
||||
preventClick: true,
|
||||
preventCheckHide: true,
|
||||
isChecked: !!data.complete_at,
|
||||
//
|
||||
complete_at: data.complete_at,
|
||||
start_at: data.start_at,
|
||||
end_at: data.end_at,
|
||||
_time: data._time,
|
||||
};
|
||||
if (data.p_name) {
|
||||
let priorityStyle = `background-color:${data.p_color}`;
|
||||
if (this.themeIsDark) {
|
||||
priorityStyle = `color:${data.p_color};border:1px solid ${data.p_color};padding:1px 3px;`;
|
||||
}
|
||||
task.priority = `<span class="priority" style="${priorityStyle}">${data.p_name}</span>`;
|
||||
}
|
||||
if (data.sub_my && data.sub_my.length > 0) {
|
||||
task.title = `[+${data.sub_my.length}] ${task.title}`
|
||||
}
|
||||
if (data.sub_top === true) {
|
||||
task.title = `[${this.$L('子任务')}] ${task.title}`
|
||||
}
|
||||
if (data.flow_item_name) {
|
||||
task.title = `[${data.flow_item_name}] ${task.title}`
|
||||
}
|
||||
if (data.complete_at) {
|
||||
task.color = "#c3c2c2"
|
||||
task.bgColor = "#f3f3f3"
|
||||
task.borderColor = "#e3e3e3"
|
||||
} else if (data.overdue) {
|
||||
task.title = `[${this.$L('超期')}] ${task.title}`
|
||||
task.color = "#f56c6c"
|
||||
task.bgColor = data.color || "#fef0f0"
|
||||
task.priority+= `<span class="overdue">${this.$L('超期未完成')}</span>`;
|
||||
}
|
||||
if (!task.borderColor) {
|
||||
task.borderColor = task.bgColor;
|
||||
}
|
||||
return task;
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
handleScroll(event) {
|
||||
// 处理滚动事件
|
||||
if(event.target.scrollTop >10){
|
||||
this.showTable = false;
|
||||
console.log('滚动事件:', event.target.scrollTop);
|
||||
}
|
||||
},
|
||||
|
||||
isCheck(data){
|
||||
let time = new Date(data.date).getTime()
|
||||
return this.list.find(h=>{
|
||||
let start = new Date(h.start).getTime()
|
||||
let end = new Date(h.end).getTime()
|
||||
return start <= time && end >= time;
|
||||
})
|
||||
},
|
||||
|
||||
getTimes(date) {
|
||||
const data = this.historys.find(item => item.date == date)
|
||||
return data?.section.map(item => {
|
||||
return `${item[0]} - ${item[1] || 'None'}`
|
||||
}).join('<br/>')
|
||||
},
|
||||
|
||||
generateCalendar(date) {
|
||||
let today = new Date($A.formatDate("Y/m/d",date))
|
||||
let one = new Date(this.year, this.month - 1, 1)
|
||||
let calcTime = one.getTime() - one.getDay() * 86400 * 1000
|
||||
let array = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
array[i] = []
|
||||
for (let j = 0; j < 7; j++) {
|
||||
let curDate = new Date(calcTime)
|
||||
let curMonth = curDate.getMonth() + 1
|
||||
array[i][j] = {
|
||||
day: curDate.getDate(),
|
||||
date: `${curDate.getFullYear()}/${curMonth}/${curDate.getDate()}`,
|
||||
today: today.getTime() == curDate.getTime(),
|
||||
future: today.getTime() < curDate.getTime(),
|
||||
month: curMonth == this.month
|
||||
}
|
||||
calcTime += 86400 * 1000
|
||||
}
|
||||
}
|
||||
this.dateArray = array
|
||||
this.startTime = array[0][0].date;
|
||||
this.endTime = array[4][6].date;
|
||||
},
|
||||
|
||||
nextMonth() {
|
||||
if (this.month == 12) {
|
||||
this.year++;
|
||||
this.month = 1;
|
||||
} else {
|
||||
this.month++;
|
||||
}
|
||||
this.generateCalendar();
|
||||
},
|
||||
|
||||
prevMonth() {
|
||||
if (this.month == 1) {
|
||||
this.year--;
|
||||
this.month = 12;
|
||||
} else {
|
||||
this.month--;
|
||||
}
|
||||
this.generateCalendar();
|
||||
},
|
||||
|
||||
nowMonth() {
|
||||
this.year = parseInt($A.formatDate("Y"));
|
||||
this.month = parseInt($A.formatDate("m"));
|
||||
this.generateCalendar();
|
||||
this.$refs.cal.getInstance().setDate(new Date());
|
||||
},
|
||||
|
||||
onDayClick(item){
|
||||
const date = new Date(item.date);
|
||||
this.year = date.getFullYear();
|
||||
this.month = date.getMonth() + 1;
|
||||
this.generateCalendar(item.date);
|
||||
this.$refs.cal.getInstance().setDate(date);
|
||||
},
|
||||
|
||||
//
|
||||
generateCalendarInstance(){
|
||||
addLanguage([
|
||||
{"key": "{日}", "zh": "日", "general": "Sun"},
|
||||
{"key": "{一}", "zh": "一", "general": "Mon"},
|
||||
{"key": "{二}", "zh": "二", "general": "Tue"},
|
||||
{"key": "{三}", "zh": "三", "general": "Wed"},
|
||||
{"key": "{四}", "zh": "四", "general": "Thu"},
|
||||
{"key": "{五}", "zh": "五", "general": "Fri"},
|
||||
{"key": "{六}", "zh": "六", "general": "Sat"},
|
||||
]);
|
||||
let daynames = [
|
||||
this.$L('{日}'),
|
||||
this.$L('{一}'),
|
||||
this.$L('{二}'),
|
||||
this.$L('{三}'),
|
||||
this.$L('{四}'),
|
||||
this.$L('{五}'),
|
||||
this.$L('{六}')
|
||||
];
|
||||
this.calendarWeek = {daynames};
|
||||
this.calendarMonth = {daynames};
|
||||
this.calendarTheme = {
|
||||
'common.border': '1px solid rgba(0,0,0,0)',
|
||||
'month.dayname.fontSize': '14px',
|
||||
'month.dayname.borderLeft': '1px solid rgba(0,0,0,0)',
|
||||
'month.dayname.height': '50px',
|
||||
}
|
||||
if (this.windowLandscape) {
|
||||
this.calendarTheme = {
|
||||
'common.border': '1px solid #f4f5f5',
|
||||
'month.dayname.fontSize': '14px',
|
||||
'month.dayname.borderLeft': '1px solid #f4f5f5',
|
||||
'month.dayname.height': '50px',
|
||||
}
|
||||
}
|
||||
this.calendarTemplate = {
|
||||
titlePlaceholder: () => {
|
||||
return this.$L("任务描述")
|
||||
},
|
||||
popupSave: () => {
|
||||
return this.$L("保存");
|
||||
},
|
||||
popupEdit: () => {
|
||||
return this.$L("详情");
|
||||
},
|
||||
popupDelete: () => {
|
||||
return this.$L("删除");
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
onBeforeCreateSchedule({start, end, isAllDay, guide}) {
|
||||
if (isAllDay || this.calendarView == 'month') {
|
||||
start = $A.date2string(start.toDate(), "Y-m-d 00:00:00")
|
||||
end = $A.date2string(end.toDate(), "Y-m-d 23:59:59")
|
||||
} else {
|
||||
start = $A.date2string(start.toDate(), "Y-m-d H:i:s")
|
||||
end = $A.date2string(end.toDate(), "Y-m-d H:i:s")
|
||||
}
|
||||
Store.set('addTask', {
|
||||
times: [start, end],
|
||||
owner: [this.userId],
|
||||
beforeClose: () => guide.clearGuideElement()
|
||||
});
|
||||
},
|
||||
|
||||
onBeforeClickSchedule(event) {
|
||||
const {type, schedule} = event;
|
||||
let data = this.cacheTasks.find(({id}) => id === schedule.id);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case "check":
|
||||
this.calendarMenuStyles = {
|
||||
left: `${this.getElementLeft(event.target)}px`,
|
||||
top: `${this.getElementTop(event.target) - 8}px`
|
||||
}
|
||||
this.calendarTask = data;
|
||||
this.$nextTick(this.$refs.calendarTaskMenu.show);
|
||||
break;
|
||||
|
||||
case "edit":
|
||||
this.$store.dispatch("openTask", data)
|
||||
break;
|
||||
|
||||
case "delete":
|
||||
$A.modalConfirm({
|
||||
title: '删除任务',
|
||||
content: '你确定要删除任务【' + data.name + '】吗?',
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$store.dispatch("removeTask", {task_id: data.id}).then(({msg}) => {
|
||||
resolve(msg);
|
||||
}).catch(({msg}) => {
|
||||
reject(msg);
|
||||
this.setRenderRange();
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onBeforeUpdateSchedule(res) {
|
||||
const {changes, schedule} = res;
|
||||
let data = this.cacheTasks.find(({id}) => id === schedule.id);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
if (changes.start || changes.end) {
|
||||
const cal = this.$refs.cal.getInstance();
|
||||
cal.updateSchedule(schedule.id, schedule.calendarId, changes);
|
||||
//
|
||||
this.$store.dispatch("taskUpdate", {
|
||||
task_id: data.id,
|
||||
times: [
|
||||
(changes.start || schedule.start).toDate(),
|
||||
(changes.end || schedule.end).toDate(),
|
||||
],
|
||||
}).then(({msg}) => {
|
||||
$A.messageSuccess(msg);
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
this.setRenderRange();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getElementLeft(element) {
|
||||
let actualLeft = element.offsetLeft;
|
||||
let current = element.offsetParent;
|
||||
while (current !== null) {
|
||||
if (current == this.$el) break;
|
||||
actualLeft += (current.offsetLeft + current.clientLeft);
|
||||
current = current.offsetParent;
|
||||
}
|
||||
return actualLeft;
|
||||
},
|
||||
|
||||
getElementTop(element) {
|
||||
let actualTop = element.offsetTop;
|
||||
let current = element.offsetParent;
|
||||
while (current !== null) {
|
||||
if (current == this.$el) break;
|
||||
actualTop += (current.offsetTop + current.clientTop);
|
||||
current = current.offsetParent;
|
||||
}
|
||||
return actualTop;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
229
resources/assets/js/pages/manage/components/ProjectMenu.vue
Normal file
229
resources/assets/js/pages/manage/components/ProjectMenu.vue
Normal file
@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<div class="project-menu">
|
||||
<PageTitle :title="$L('项目')"/>
|
||||
<div class="list-search">
|
||||
<div class="search-wrapper">
|
||||
<Input v-model="projectKeyValue" type="text" :placeholder="$L(loadProjects ? '更新中...' : '搜索项目')" clearable>
|
||||
<div class="search-pre" slot="prefix">
|
||||
<Loading v-if="loadProjects"/>
|
||||
<Icon v-else type="ios-search" />
|
||||
</div>
|
||||
</Input>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="menuProject" class="menu-project" >
|
||||
<ul v-if="projectLists.length > 0">
|
||||
<li
|
||||
v-for="(item, key) in projectLists"
|
||||
:ref="`project_${item.id}`"
|
||||
:key="key"
|
||||
:class="classNameProject(item)"
|
||||
:data-id="item.id"
|
||||
@click="toggleRoute('project', {projectId: item.id})"
|
||||
v-longpress="handleLongpress">
|
||||
<div class="project-h1">
|
||||
<em @click.stop="toggleOpenMenu(item.id)"></em>
|
||||
<div class="title">{{item.name}}</div>
|
||||
<div v-if="item.top_at" class="icon-top"></div>
|
||||
<div v-if="item.task_my_num - item.task_my_complete > 0" class="num">{{item.task_my_num - item.task_my_complete}}</div>
|
||||
</div>
|
||||
<div class="project-h2">
|
||||
<p>
|
||||
<em>{{$L('我的')}}:</em>
|
||||
<span>{{item.task_my_complete}}/{{item.task_my_num}}</span>
|
||||
<Progress :percent="item.task_my_percent" :stroke-width="6" />
|
||||
</p>
|
||||
<p>
|
||||
<em>{{$L('全部')}}:</em>
|
||||
<span>{{item.task_complete}}/{{item.task_num}}</span>
|
||||
<Progress :percent="item.task_percent" :stroke-width="6" />
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="projectKeyLoading > 0" class="loading"><Loading/></li>
|
||||
</ul>
|
||||
<div v-else>
|
||||
{{$L(projectKeyValue ? `没有与"${projectKeyValue}"相关的项目` : `没有任何项目`)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="operate-position" :style="operateStyles" v-show="operateVisible">
|
||||
<Dropdown
|
||||
trigger="custom"
|
||||
:placement="windowLandscape ? 'bottom' : 'top'"
|
||||
:visible="operateVisible"
|
||||
@on-clickoutside="operateVisible = false"
|
||||
transfer>
|
||||
<div :style="{userSelect:operateVisible ? 'none' : 'auto', height: operateStyles.height}"></div>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem @click.native="handleTopClick">
|
||||
{{ $L(operateItem.top_at ? '取消置顶' : '置顶该项目') }}
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import longpress from "../../../directives/longpress";
|
||||
|
||||
export default {
|
||||
name: "ProjectLists",
|
||||
directives: {longpress},
|
||||
props: {
|
||||
projectId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
openMenu: {},
|
||||
|
||||
projectKeyValue: '',
|
||||
projectKeyLoading: 0,
|
||||
projectSearchShow: false,
|
||||
|
||||
operateStyles: {},
|
||||
operateVisible: false,
|
||||
operateItem: {},
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['cacheProjects', 'loadProjects']),
|
||||
|
||||
routeName() {
|
||||
return this.$route.name
|
||||
},
|
||||
|
||||
projectLists() {
|
||||
const {projectKeyValue, cacheProjects} = this;
|
||||
const data = $A.cloneJSON(cacheProjects).sort((a, b) => {
|
||||
if (a.top_at || b.top_at) {
|
||||
return $A.Date(b.top_at) - $A.Date(a.top_at);
|
||||
}
|
||||
return b.id - a.id;
|
||||
});
|
||||
if (projectKeyValue) {
|
||||
return data.filter(item => $A.strExists(`${item.name} ${item.desc}`, projectKeyValue));
|
||||
}
|
||||
return data;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
||||
projectKeyValue(val) {
|
||||
if (val == '') {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (this.projectKeyValue == val) {
|
||||
this.searchProject();
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
|
||||
'cacheProjects.length': {
|
||||
handler() {
|
||||
this.$nextTick(_ => {
|
||||
const menuProject = this.$refs.menuProject
|
||||
const lastEl = $A.last($A.getObject(menuProject, 'children.0.children'))
|
||||
if (lastEl) {
|
||||
const lastRect = lastEl.getBoundingClientRect()
|
||||
const menuRect = menuProject.getBoundingClientRect()
|
||||
if (lastRect.top > menuRect.top + menuRect.height) {
|
||||
this.projectSearchShow = true
|
||||
return
|
||||
}
|
||||
}
|
||||
this.projectSearchShow = false
|
||||
})
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
handleLongpress(event, el) {
|
||||
const projectId = $A.getAttr(el, 'data-id')
|
||||
const projectItem = this.projectLists.find(item => item.id == projectId)
|
||||
if (!projectItem) {
|
||||
return
|
||||
}
|
||||
this.operateVisible = false;
|
||||
this.operateItem = $A.isJson(projectItem) ? projectItem : {};
|
||||
this.$nextTick(() => {
|
||||
const projectRect = el.getBoundingClientRect();
|
||||
const wrapRect = this.$refs.menuProject.getBoundingClientRect();
|
||||
this.operateStyles = {
|
||||
left: `${event.clientX - wrapRect.left}px`,
|
||||
top: `${projectRect.top + this.windowScrollY}px`,
|
||||
height: projectRect.height + 'px',
|
||||
}
|
||||
this.operateVisible = true;
|
||||
})
|
||||
},
|
||||
|
||||
classNameProject(item) {
|
||||
return {
|
||||
"active": this.routeName === 'manage-project' && (this.projectId || this.$route.params.projectId) == item.id,
|
||||
"open-menu": this.openMenu[item.id] === true,
|
||||
"operate": item.id == this.operateItem.id && this.operateVisible
|
||||
};
|
||||
},
|
||||
|
||||
toggleOpenMenu(id) {
|
||||
this.$set(this.openMenu, id, !this.openMenu[id])
|
||||
},
|
||||
|
||||
async toggleRoute(path, params) {
|
||||
this.showMobileMenu = false;
|
||||
let location = {name: 'manage-' + path, params: params || {}};
|
||||
let fileFolderId = await $A.IDBInt("fileFolderId");
|
||||
if (path === 'file' && fileFolderId > 0) {
|
||||
location.params.folderId = fileFolderId
|
||||
}
|
||||
this.goForward(location);
|
||||
},
|
||||
|
||||
searchProject() {
|
||||
setTimeout(() => {
|
||||
this.projectKeyLoading++;
|
||||
}, 1000)
|
||||
this.$store.dispatch("getProjects", {
|
||||
keys: {
|
||||
name: this.projectKeyValue
|
||||
}
|
||||
}).finally(_ => {
|
||||
this.projectKeyLoading--;
|
||||
});
|
||||
},
|
||||
|
||||
handleTopClick() {
|
||||
this.$store.dispatch("call", {
|
||||
url: 'project/top',
|
||||
data: {
|
||||
project_id: this.operateItem.id,
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.$store.dispatch("saveProject", data);
|
||||
this.$nextTick(() => {
|
||||
const active = this.$refs.menuProject.querySelector(".active")
|
||||
if (active) {
|
||||
$A.scrollIntoViewIfNeeded(active);
|
||||
}
|
||||
});
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="page-dashboard">
|
||||
<div class="page-dashboard" style="flex-direction: row;">
|
||||
<PageTitle :title="$L('仪表盘')"/>
|
||||
<Alert v-if="warningMsg" class="dashboard-warning" type="warning" show-icon>
|
||||
<span @click="goForward({name: 'manage-setting-license'})">{{warningMsg}}</span>
|
||||
@ -83,15 +83,19 @@
|
||||
</template>
|
||||
</Scrollbar>
|
||||
</div>
|
||||
<div v-if="1" style="width: 35%;min-width:400px;height: 100%;border-left: 1px solid #F4F5F7;">
|
||||
<HomeCalendar/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters, mapState} from "vuex";
|
||||
import TaskMenu from "./components/TaskMenu";
|
||||
import HomeCalendar from "./components/HomeCalendar";
|
||||
|
||||
export default {
|
||||
components: {TaskMenu},
|
||||
components: {TaskMenu, HomeCalendar},
|
||||
data() {
|
||||
return {
|
||||
nowTime: $A.Time(),
|
||||
|
||||
@ -52,62 +52,63 @@
|
||||
@touchstart.native="listTouch"
|
||||
@on-scroll="listScroll">
|
||||
<ul v-if="tabActive==='dialog'" ref="ul" class="dialog">
|
||||
<li
|
||||
v-if="dialogList.length > 0"
|
||||
v-for="(dialog, key) in dialogList"
|
||||
:ref="`dialog_${dialog.id}`"
|
||||
:key="key"
|
||||
:data-id="dialog.id"
|
||||
:class="dialogClass(dialog)"
|
||||
@click="openDialog({
|
||||
dialog_id: dialog.id,
|
||||
search_msg_id: dialog.search_msg_id
|
||||
})"
|
||||
v-longpress="handleLongpress"
|
||||
:style="{'background-color':dialog.color}">
|
||||
<template v-if="dialog.type=='group'">
|
||||
<EAvatar v-if="dialog.avatar" class="img-avatar" :src="dialog.avatar" :size="42"></EAvatar>
|
||||
<i v-else-if="dialog.group_type=='department'" class="taskfont icon-avatar department"></i>
|
||||
<i v-else-if="dialog.group_type=='project'" class="taskfont icon-avatar project"></i>
|
||||
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task"></i>
|
||||
<i v-else-if="dialog.group_type=='okr'" class="taskfont icon-avatar task"></i>
|
||||
<Icon v-else class="icon-avatar" type="ios-people" />
|
||||
</template>
|
||||
<div v-else-if="dialog.dialog_user" class="user-avatar"><UserAvatar :userid="dialog.dialog_user.userid" :size="42"/></div>
|
||||
<Icon v-else class="icon-avatar" type="md-person" />
|
||||
<div class="dialog-box">
|
||||
<div class="dialog-title">
|
||||
<div v-if="dialog.todo_num" class="todo">[{{$L('待办')}}{{formatTodoNum(dialog.todo_num)}}]</div>
|
||||
<div v-if="$A.getDialogMention(dialog) > 0" class="mention">[@{{$A.getDialogMention(dialog)}}]</div>
|
||||
<div v-if="dialog.bot" class="taskfont bot"></div>
|
||||
<template v-for="tag in $A.dialogTags(dialog)" v-if="tag.color != 'success'">
|
||||
<Tag :color="tag.color" :fade="false" @on-click="openDialog(dialog.id)">{{$L(tag.text)}}</Tag>
|
||||
</template>
|
||||
<span>{{dialog.name}}</span>
|
||||
<Icon v-if="dialog.type == 'user' && lastMsgReadDone(dialog.last_msg) && dialog.dialog_user.userid != userId" :type="lastMsgReadDone(dialog.last_msg)"/>
|
||||
<em v-if="dialog.last_at">{{$A.formatTime(dialog.last_at)}}</em>
|
||||
</div>
|
||||
<div class="dialog-text no-dark-content">
|
||||
<template v-if="dialog.extra_draft_has && dialog.id != dialogId">
|
||||
<div class="last-draft">[{{$L('草稿')}}]</div>
|
||||
<div class="last-text"><span>{{formatDraft(dialog.extra_draft_content)}}</span></div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="dialog.type=='group' && dialog.last_msg && dialog.last_msg.userid">
|
||||
<div v-if="dialog.last_msg.userid == userId" class="last-self">{{$L('你')}}</div>
|
||||
<UserAvatar v-else :userid="dialog.last_msg.userid" :show-name="true" :show-icon="false" tooltip-disabled/>
|
||||
<template v-if="dialogList.length > 0">
|
||||
<li
|
||||
v-for="(dialog, key) in dialogList"
|
||||
:ref="`dialog_${dialog.id}`"
|
||||
:key="key"
|
||||
:data-id="dialog.id"
|
||||
:class="dialogClass(dialog)"
|
||||
@click="openDialog({
|
||||
dialog_id: dialog.id,
|
||||
search_msg_id: dialog.search_msg_id
|
||||
})"
|
||||
v-longpress="handleLongpress"
|
||||
:style="{'background-color':dialog.color}">
|
||||
<template v-if="dialog.type=='group'">
|
||||
<EAvatar v-if="dialog.avatar" class="img-avatar" :src="dialog.avatar" :size="42"></EAvatar>
|
||||
<i v-else-if="dialog.group_type=='department'" class="taskfont icon-avatar department"></i>
|
||||
<i v-else-if="dialog.group_type=='project'" class="taskfont icon-avatar project"></i>
|
||||
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task"></i>
|
||||
<i v-else-if="dialog.group_type=='okr'" class="taskfont icon-avatar task"></i>
|
||||
<Icon v-else class="icon-avatar" type="ios-people" />
|
||||
</template>
|
||||
<div v-else-if="dialog.dialog_user" class="user-avatar"><UserAvatar :userid="dialog.dialog_user.userid" :size="42"/></div>
|
||||
<Icon v-else class="icon-avatar" type="md-person" />
|
||||
<div class="dialog-box">
|
||||
<div class="dialog-title">
|
||||
<div v-if="dialog.todo_num" class="todo">[{{$L('待办')}}{{formatTodoNum(dialog.todo_num)}}]</div>
|
||||
<div v-if="$A.getDialogMention(dialog) > 0" class="mention">[@{{$A.getDialogMention(dialog)}}]</div>
|
||||
<div v-if="dialog.bot" class="taskfont bot"></div>
|
||||
<template v-for="tag in $A.dialogTags(dialog)" v-if="tag.color != 'success'">
|
||||
<Tag :color="tag.color" :fade="false" @on-click="openDialog(dialog.id)">{{$L(tag.text)}}</Tag>
|
||||
</template>
|
||||
<div class="last-text">
|
||||
<em v-if="formatMsgEmojiDesc(dialog.last_msg)">{{formatMsgEmojiDesc(dialog.last_msg)}}</em>
|
||||
<span>{{$A.getMsgSimpleDesc(dialog.last_msg)}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="dialog.silence" class="taskfont last-silence"></div>
|
||||
<span>{{dialog.name}}</span>
|
||||
<Icon v-if="dialog.type == 'user' && lastMsgReadDone(dialog.last_msg) && dialog.dialog_user.userid != userId" :type="lastMsgReadDone(dialog.last_msg)"/>
|
||||
<em v-if="dialog.last_at">{{$A.formatTime(dialog.last_at)}}</em>
|
||||
</div>
|
||||
<div class="dialog-text no-dark-content">
|
||||
<template v-if="dialog.extra_draft_has && dialog.id != dialogId">
|
||||
<div class="last-draft">[{{$L('草稿')}}]</div>
|
||||
<div class="last-text"><span>{{formatDraft(dialog.extra_draft_content)}}</span></div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="dialog.type=='group' && dialog.last_msg && dialog.last_msg.userid">
|
||||
<div v-if="dialog.last_msg.userid == userId" class="last-self">{{$L('你')}}</div>
|
||||
<UserAvatar v-else :userid="dialog.last_msg.userid" :show-name="true" :show-icon="false" tooltip-disabled/>
|
||||
</template>
|
||||
<div class="last-text">
|
||||
<em v-if="formatMsgEmojiDesc(dialog.last_msg)">{{formatMsgEmojiDesc(dialog.last_msg)}}</em>
|
||||
<span>{{$A.getMsgSimpleDesc(dialog.last_msg)}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="dialog.silence" class="taskfont last-silence"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Badge class="dialog-num" :type="dialog.silence ? 'normal' : 'error'" :overflow-count="999" :count="$A.getDialogUnread(dialog, true)"/>
|
||||
<div class="dialog-line"></div>
|
||||
</li>
|
||||
<Badge class="dialog-num" :type="dialog.silence ? 'normal' : 'error'" :overflow-count="999" :count="$A.getDialogUnread(dialog, true)"/>
|
||||
<div class="dialog-line"></div>
|
||||
</li>
|
||||
</template>
|
||||
<li v-else-if="dialogSearchLoad === 0" class="nothing">
|
||||
{{$L(dialogSearchKey ? `没有任何与"${dialogSearchKey}"相关的会话` : `没有任何会话`)}}
|
||||
</li>
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
<template>
|
||||
<div class="page-project">
|
||||
<template v-if="projectId > 0">
|
||||
<ProjectMenu v-if="!windowPortrait" :projectId="projId"/>
|
||||
<template v-if="projId > 0">
|
||||
<ProjectPanel/>
|
||||
<ProjectDialog/>
|
||||
</template>
|
||||
<ProjectList v-if="windowPortrait" v-show="projectId === 0"/>
|
||||
<div v-else class="page-project-empty">
|
||||
<div><i class="taskfont"></i></div>
|
||||
<span>{{ $L('选择一个项目查看更多任务') }}</span>
|
||||
</div>
|
||||
<ProjectList v-if="windowPortrait" v-show="projId === 0"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -13,24 +18,25 @@ import {mapState} from "vuex";
|
||||
import ProjectPanel from "./components/ProjectPanel";
|
||||
import ProjectDialog from "./components/ProjectDialog";
|
||||
import ProjectList from "./components/ProjectList";
|
||||
import ProjectMenu from "./components/ProjectMenu";
|
||||
export default {
|
||||
components: {ProjectList, ProjectDialog, ProjectPanel},
|
||||
components: {ProjectList, ProjectMenu, ProjectDialog, ProjectPanel},
|
||||
|
||||
deactivated() {
|
||||
this.$store.dispatch("forgetTaskCompleteTemp", true);
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['cacheProjects', 'wsOpenNum']),
|
||||
...mapState(['cacheProjects', 'wsOpenNum', 'projectId']),
|
||||
|
||||
projectId() {
|
||||
projId() {
|
||||
const {projectId} = this.$route.params;
|
||||
return parseInt(/^\d+$/.test(projectId) ? projectId : 0);
|
||||
return parseInt(/^\d+$/.test(projectId) ? projectId : 0) || this.projectId || 0;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
projectId: {
|
||||
projId: {
|
||||
handler() {
|
||||
this.getProjectData();
|
||||
},
|
||||
@ -48,15 +54,15 @@ export default {
|
||||
|
||||
methods: {
|
||||
getProjectData() {
|
||||
if (this.projectId <= 0) return;
|
||||
const projectId = this.projectId;
|
||||
if (this.projId <= 0) return;
|
||||
const projId = this.projId;
|
||||
this.$nextTick(() => {
|
||||
this.$store.state.projectId = projectId;
|
||||
this.$store.dispatch("getProjectOne", projectId).then(() => {
|
||||
this.$store.dispatch("getColumns", projectId).catch(() => {});
|
||||
this.$store.dispatch("getTaskForProject", projectId).catch(() => {})
|
||||
this.$store.state.projectId = projId;
|
||||
this.$store.dispatch("getProjectOne", projId).then(() => {
|
||||
this.$store.dispatch("getColumns", projId).catch(() => {});
|
||||
this.$store.dispatch("getTaskForProject", projId).catch(() => {})
|
||||
}).catch(({msg}) => {
|
||||
if (projectId !== this.projectId) {
|
||||
if (projId !== this.projId) {
|
||||
return;
|
||||
}
|
||||
$A.modalWarning({
|
||||
|
||||
2
resources/assets/js/routes.js
vendored
2
resources/assets/js/routes.js
vendored
@ -113,7 +113,7 @@ export default [
|
||||
},
|
||||
{
|
||||
name: 'manage-project',
|
||||
path: 'project/:projectId',
|
||||
path: 'project/:projectId?',
|
||||
component: () => import('./pages/manage/project.vue'),
|
||||
},
|
||||
{
|
||||
|
||||
@ -25,3 +25,5 @@
|
||||
@import "team-management";
|
||||
@import "update-log";
|
||||
@import "task-exist-tips";
|
||||
@import "project-menu";
|
||||
@import "home-calendar";
|
||||
|
||||
270
resources/assets/sass/pages/components/home-calendar.scss
vendored
Normal file
270
resources/assets/sass/pages/components/home-calendar.scss
vendored
Normal file
@ -0,0 +1,270 @@
|
||||
.home-calendar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #555;
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 32px 0;
|
||||
overflow: auto;
|
||||
|
||||
.calendar-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 24px;
|
||||
.calendar-header-menu {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
font-size: 24px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.calendar-header-back {
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollbar-content{
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.calendar-content{
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.slide-up-enter-active,
|
||||
.slide-up-leave-active {
|
||||
transition: all 0.1s ease-out;
|
||||
}
|
||||
|
||||
.slide-up-enter,
|
||||
.slide-up-leave-to {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.calendar-loading {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
background-color: rgba(55, 55, 55, .15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.calendar-table {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
th {
|
||||
text-align: center;
|
||||
height: 48px;
|
||||
font-weight: 700;
|
||||
opacity: 0.4;
|
||||
}
|
||||
td {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
height: 46px;
|
||||
.item-day {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
> div {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
max-width: 100%;
|
||||
padding: 0 4px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
border-radius: 30px;
|
||||
}
|
||||
.badge{
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: #8FCE78;
|
||||
border-radius: 100%;
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
&.disabled {
|
||||
color: #ccc;
|
||||
background: none;
|
||||
* {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
&.today {
|
||||
.item-day {
|
||||
> div {
|
||||
background-color: #8FCE78;
|
||||
color: #fff;
|
||||
}
|
||||
.badge{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
.calendar-tui{
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
margin-top: 22px;
|
||||
border-top: 1px solid #F2F2F2;
|
||||
// .tui-full-calendar-vlayout-area>div:nth-child(3){
|
||||
// height: 300px !important;
|
||||
// }
|
||||
// .tui-full-calendar-dayname-layout{
|
||||
// display: none;
|
||||
// }
|
||||
// .tui-full-calendar-left,.tui-full-calendar-timegrid-left{
|
||||
// width: 45px !important;
|
||||
// }
|
||||
// .tui-full-calendar-timegrid-right{
|
||||
// margin-left: 45px !important;
|
||||
// }
|
||||
// .tui-full-calendar-popup {
|
||||
// box-shadow: none;
|
||||
// margin-left: 5px;
|
||||
// .tui-full-calendar-section-header {
|
||||
// .tui-full-calendar-ic-checkbox-checked {
|
||||
// background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAhFBMVEUAAACLz3CLz3CLz3CKzm6Gy2+Lz3CLz3CL0HCLz3CLz3CLz3CLz3CMz3GLz3CKz3CLz3CL0HCJ0G+KznCN0HCL0HCLz3CKz3CLz3CLz3CLz3CMz3CLz3CLz3GL0XCL0HCN0XKLz3CLz3CMz3CLz3CM0HCM0G+FzHCLz3CKz3CMz3CLz3Bod5CFAAAAK3RSTlMA18RAOQ3s8+Pc0rmyq3tpiUwTgBnovyDMjmNSRjUvJQX5yKB0WisKppuUFLaY7gAAAotJREFUeNrtm+FymkAUhc8KqIAgSkyUtkmsmqa97/9+HWeSudpCd8qZ7E0m+73A9/1gxmXx4IK0nbipvDFTN2lT9JDVToLh6gx/sHQSFLfEFZUEp8IFczFgrv5CTChe/TsxYvfy/IkZy7M/c2KGywDUYkgNIBdDciARUxI0YkqDiZgygRNTHKZiyhRiTAyIATEgBsSAGBADYsAnCJgdmtIywKUAOrsA94QzJyKA95/pbALcPV7piADGryzDB+Rnv3IkAhi/UhMBjF9pQwbk3/A3JRXA+7GjAng/DqEC5v3+dMYE8P6nQsIEzFOPnw7g/QpC+R8K4QJ4f5iAzaA/TMAm6fdvZQgY+wW2fn9A0a66Bee/2xLH8kp/Rr1MB/3jAxaP0ALCPzagzPBCM9r/XcYH3K4BLfD4vw75xwdMbqB4CmaD/vEB2ztc0RD+MQHFg+c85fffDPv9AbPUd6Lz+ydCBDyjh1//6WcCGngK1L8a8lMBJTwFfj8XIC16+SnX7Af9bIDUngLSrwFEwaD/VogA5YheDj7/Wv1MgL9g/8XjpwNk+c8Cyq8BYwqePX46QOkGCmi/BowrqFi/Bvg4wYv6y7e4Kz4Rfj5AnzY/WSlcwHAB5+cD9ivKzwfIbEX4qQA99RB+NkDfO4b5sRAigHjzpP0C6u6D9wuo2z/eL+DvXx8Zv4C4gVd/qABxCeFnApQT5+cDpOP8fICcLv2VxbfjlQZUNh+vU/XbBIj6jQLm9wDWlZgFyOaYHJ3Ix/gDQwyIATEgBsSAGODBfuBgPvEwH7m0YkqLVExJYfsQuPcwdjOf+5kPHoFKjKio0e3Hn90WUCyGt7v3Nf0GsjqXYOR1hh6SJsz8v0mg/AZRXmaRKXtJBwAAAABJRU5ErkJggg==);
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-popup-container {
|
||||
// border: 0;
|
||||
// box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
|
||||
// border-radius: 6px;
|
||||
// }
|
||||
// .tui-full-calendar-arrow-top .tui-full-calendar-popup-arrow-border {
|
||||
// top: -8px;
|
||||
// border-bottom-color: rgba(217, 217, 217, .5);
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-dropdown-menu {
|
||||
// border-color: #e8e8e8;
|
||||
// width: calc(100% - 14px);
|
||||
// }
|
||||
// .tui-full-calendar-popup-creation {
|
||||
// .tui-full-calendar-icon {
|
||||
// &.tui-full-calendar-ic-title,
|
||||
// &.tui-full-calendar-calendar-dot {
|
||||
// display: none;
|
||||
// }
|
||||
// &.tui-full-calendar-ic-date {
|
||||
// background-image: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNjIzODU5NjcwNjA3IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE2Mzg4IiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0iTTk2MCAxMjhIODMzYzAtNTMtNDMtOTYtOTYtOTZoLTE2Yy01MyAwLTk2IDQzLTk2IDk2SDQwMGMwLTI2LjUtMTAuNy01MC41LTI4LjEtNjcuOUMzNTQuNSA0Mi43IDMzMC41IDMyIDMwNCAzMmgtMTZjLTUzIDAtOTYgNDMtOTYgOTZINjRjLTM1LjMgMC02NCAyOC42LTY0IDY0djczNmMwIDM1LjMgMjguNyA2NCA2NCA2NGg4OTZjMzUuMyAwIDY0LTI4LjcgNjQtNjRWMTkyYzAtMzUuNC0yOC43LTY0LTY0LTY0eiBtLTI3MSA4YzAtMjIuMSAxNy45LTQwIDQwLTQwczQwIDE3LjkgNDAgNDB2ODBjMCAyMi4xLTE3LjkgNDAtNDAgNDAtMTEgMC0yMS00LjUtMjguMy0xMS43QzY5My41IDIzNyA2ODkgMjI3IDY4OSAyMTZ2LTgweiBtLTQzMyAwYzAtMjIuMSAxNy45LTQwIDQwLTQwczQwIDE3LjkgNDAgNDB2ODBjMCAyMi4xLTE3LjkgNDAtNDAgNDAtMTEgMC0yMS00LjUtMjguMy0xMS43QzI2MC41IDIzNyAyNTYgMjI3IDI1NiAyMTZ2LTgweiBtNzA0IDc2MGMwIDE3LjctMTQuMyAzMi0zMiAzMkg5NmMtMTcuNyAwLTMyLTE0LjMtMzItMzJWNDQ4aDg5NnY0NDh6IiBwLWlkPSIxNjM4OSIgZmlsbD0iIzUxNTE1MSI+PC9wYXRoPjwvc3ZnPg==");
|
||||
// background-size: contain;
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-content {
|
||||
// padding-left: 0;
|
||||
// }
|
||||
// .tui-full-calendar-popup-section {
|
||||
// display: flex;
|
||||
// justify-content: space-between;
|
||||
// margin-bottom: 10px;
|
||||
// .tui-full-calendar-popup-section-item {
|
||||
// height: 36px;
|
||||
// line-height: 34px;
|
||||
// border-color: #e8e8e8;
|
||||
// border-radius: 4px;
|
||||
// }
|
||||
// .tui-full-calendar-popup-section-item input {
|
||||
// height: 34px;
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-section-title {
|
||||
// width: 100%;
|
||||
// input {
|
||||
// width: 100%;
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-section-start-date,
|
||||
// .tui-full-calendar-section-end-date {
|
||||
// width: 210px;
|
||||
// .tui-full-calendar-content {
|
||||
// padding-left: 8px;
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-popup-location,
|
||||
// .tui-full-calendar-section-private,
|
||||
// .tui-full-calendar-section-allday,
|
||||
// .tui-full-calendar-section-state {
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-popup-task {
|
||||
// .priority {
|
||||
// color: #ffffff;
|
||||
// padding: 2px 4px;
|
||||
// border-radius: 4px;
|
||||
// margin-right: 6px;
|
||||
// }
|
||||
// .overdue {
|
||||
// color: #f5222d;
|
||||
// background: #fff1f0;
|
||||
// border: 1px solid #ffa39e;
|
||||
// padding: 1px 3px;
|
||||
// border-radius: 4px;
|
||||
// margin-right: 6px;
|
||||
// }
|
||||
// .tui-full-calendar-calendar-dot,
|
||||
// .tui-full-calendar-ic-priority {
|
||||
// opacity: 0;
|
||||
// }
|
||||
// .tui-full-calendar-ic-edit {
|
||||
// top: -2px;
|
||||
// background-image: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNjIzODU5MzY4MTg5IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjExMTkiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNODMzLjQyODU3MTY4IDYySDE5MC41NzE0MjgzMmExMjguNTcxNDI4MzIgMTI4LjU3MTQyODMyIDAgMCAwLTEyOC41NzE0MjgzMiAxMjguNTcxNDI4MzJ2NjQyLjg1NzE0MzM2YTEyOC41NzE0MjgzMiAxMjguNTcxNDI4MzIgMCAwIDAgMTI4LjU3MTQyODMyIDEyOC41NzE0MjgzMmg2NDIuODU3MTQzMzZhMTI4LjU3MTQyODMyIDEyOC41NzE0MjgzMiAwIDAgMCAxMjguNTcxNDI4MzItMTI4LjU3MTQyODMyVjE5MC41NzE0MjgzMmExMjguNTcxNDI4MzIgMTI4LjU3MTQyODMyIDAgMCAwLTEyOC41NzE0MjgzMi0xMjguNTcxNDI4MzJ6IG02NC4yODU3MTQxNiA3NzEuNDI4NTcxNjhhNjQuMjg1NzE0MTYgNjQuMjg1NzE0MTYgMCAwIDEtNjQuMjg1NzE0MTcgNjQuMjg1NzE0MTZIMTkwLjU3MTQyODMyYTY0LjI4NTcxNDE2IDY0LjI4NTcxNDE2IDAgMCAxLTY0LjI4NTcxNDE2LTY0LjI4NTcxNDE2VjE5MC41NzE0MjgzMmE2NC4yODU3MTQxNiA2NC4yODU3MTQxNiAwIDAgMSA2NC4yODU3MTQxNy02NC4yODU3MTQxNmg2NDIuODU3MTQzMzVhNjQuMjg1NzE0MTYgNjQuMjg1NzE0MTYgMCAwIDEgNjQuMjg1NzE0MTYgNjQuMjg1NzE0MTd6IiBwLWlkPSIxMTIwIiBmaWxsPSIjNTE1MTUxIj48L3BhdGg+PHBhdGggZD0iTTE5MC41NzE0MjgzMiAyNTQuODU3MTQyNDhoNjQuMjg1NzE0MTZ2NjQuMjg1NzE1MDRIMTkwLjU3MTQyODMyek0zMTkuMTQyODU3NTIgMjU0Ljg1NzE0MjQ4aDQ1MHY2NC4yODU3MTUwNEgzMTkuMTQyODU3NTJ6TTE5MC41NzE0MjgzMiA0NDcuNzE0Mjg1ODRoNjQuMjg1NzE0MTZ2NjQuMjg1NzE0MTZIMTkwLjU3MTQyODMyek0zMTkuMTQyODU3NTIgNDQ3LjcxNDI4NTg0aDQ1MHY2NC4yODU3MTQxNkgzMTkuMTQyODU3NTJ6TTE5MC41NzE0MjgzMiA2NDAuNTcxNDI4MzJoNjQuMjg1NzE0MTZ2NjQuMjg1NzE0MTZIMTkwLjU3MTQyODMyek0zMTkuMTQyODU3NTIgNjQwLjU3MTQyODMyaDMyMS40Mjg1NzA4djY0LjI4NTcxNDE2SDMxOS4xNDI4NTc1MnoiIHAtaWQ9IjExMjEiIGZpbGw9IiM1MTUxNTEiPjwvcGF0aD48L3N2Zz4=");
|
||||
// }
|
||||
// .tui-full-calendar-ic-delete {
|
||||
// top: -2px;
|
||||
// background-image: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNjIzODU5MzMwMTc2IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9Ijc5MiIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiPjxwYXRoIGQ9Ik04OTIuMjg4IDI1NmgtMTkxLjE2OEEyMDIuMjQgMjAyLjI0IDAgMCAwIDUwOS42MzIgNjIuMDggMjAxLjIxNiAyMDEuMjE2IDAgMCAwIDMxOC44NDggMjU2SDEyOGMtMTguNjg4IDAtNjYuMDQ4LTQuMjI0LTY2LjA0OCAyNC43NjhDNjEuOTUyIDMyNy43NDQgMTA5LjM3NiAzMjAgMTI4IDMyMGg2NHY1MTJhMTQ2LjQ5NiAxNDYuNDk2IDAgMCAwIDEyNy40MjQgMTI4aDM4Mi4yNzJBMTUwLjAxNiAxNTAuMDE2IDAgMCAwIDgzMiA4MzJsLTMuMzkyLTUxMmg2NGMxOC4zNjggMCA2NS4wMjQgMS40NzIgNjUuMDI0LTM5Ljc0NEE3Mi4zODQgNzIuMzg0IDAgMCAwIDg5Mi4yODggMjU2ek01MDkuNjMyIDEyOC41MTJBMTM4LjE3NiAxMzguMTc2IDAgMCAxIDYzNy40NCAyNTZIMzgyLjU5MmExMzcuOTIgMTM3LjkyIDAgMCAxIDEyNy4wNC0xMjcuNDg4ek03NjggODMyYTk3Ljk4NCA5Ny45ODQgMCAwIDEtNjYuODggNjRIMzE4Ljg0OGE5My41NjggOTMuNTY4IDAgMCAxLTY0LTY0VjMyMEg3Njh2NTEyeiBtLTM4NS40MDgtNjRWNTEyYzAtMTguNDk2IDAuOTYtNjAuOTkyIDM2LjczNi02MC45OTIgMjcuMzI4IDAgMjYuNDk2IDQzLjAwOCAyNi45NDQgNjAuOTkydjI1NmMwIDE4LjQ5Ni02LjQgMjAuMDMyLTI0Ljk2IDIwLjAzMnMtMzguNzItMS41MzYtMzguNzItMjAuMDMyeiBtMTkxLjE2OCAwVjUxMmE2NCA2NCAwIDAgMSAyMy44MDgtNjAuOTkyYzQyLjQzMiAwIDM5LjM2IDQzLjAwOCAzOS44NzIgNjAuOTkydjI1NmMwIDE4LjQ5Ni0xOS41ODQgMjAuMDMyLTM3Ljk1MiAyMC4wMzJzLTI1Ljc5Mi0xLjUzNi0yNS43OTItMjAuMDMyeiIgcC1pZD0iNzkzIiBmaWxsPSIjNTE1MTUxIj48L3BhdGg+PC9zdmc+");
|
||||
// }
|
||||
// .tui-full-calendar-popup-detail-item-separate {
|
||||
// padding-left: 22px;
|
||||
// }
|
||||
// }
|
||||
// .tui-datepicker {
|
||||
// border-color: #e8e8e8;
|
||||
// .tui-calendar {
|
||||
// th,
|
||||
// td {
|
||||
// height: 32px;
|
||||
// }
|
||||
// .tui-calendar-prev-month.tui-calendar-date,
|
||||
// .tui-calendar-next-month.tui-calendar-date {
|
||||
// visibility: visible;
|
||||
// }
|
||||
// }
|
||||
// .tui-datepicker-body .tui-timepicker,
|
||||
// .tui-datepicker-footer .tui-timepicker {
|
||||
// padding: 16px 46px 16px 47px;
|
||||
// }
|
||||
// }
|
||||
// .tui-full-calendar-popup-detail-item {
|
||||
// word-break: break-all;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
220
resources/assets/sass/pages/components/project-menu.scss
vendored
Normal file
220
resources/assets/sass/pages/components/project-menu.scss
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
.project-menu {
|
||||
padding-top: 20px;
|
||||
background-color: #ffffff;
|
||||
width: 240px;
|
||||
max-width: 240px;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
padding-bottom: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right:1px solid #F4F5F7;
|
||||
|
||||
.list-search {
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 54px;
|
||||
padding: 0 12px;
|
||||
|
||||
.search-wrapper {
|
||||
flex: 1;
|
||||
background-color: #F4F5F7;
|
||||
padding: 0 8px;
|
||||
margin: 0 4px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
|
||||
.search-pre {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.common-loading {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ivu-input {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-project {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
cursor: default;
|
||||
margin: 0 auto;
|
||||
width: 90%;
|
||||
overflow: auto;
|
||||
padding: 5px 5px 0 0;
|
||||
> ul {
|
||||
width: 100%;
|
||||
> li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
margin: 2px auto;
|
||||
border: 2px solid transparent;
|
||||
.project-h1 {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px 0 28px;
|
||||
border-radius: 8px;
|
||||
> em {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 2px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:before {
|
||||
content: "";
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNjIyMzkwODExNTQxIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjI0OTk3IiB3aWR0aD0iNDgiIGhlaWdodD0iNDgiPjxwYXRoIGQ9Ik0zNjYuMTgyNCAxMDguMjM2OEw4MTIuMDMyIDQyOC4wMzJhMTAyLjQgMTAyLjQgMCAwIDEgMCAxNjYuNTAyNEwzNjYuMTgyNCA5MTQuMzI5NmExMDIuNCAxMDIuNCAwIDAgMS0xNjIuMDk5Mi04My4yNTEyVjE5MS40ODhhMTAyLjQgMTAyLjQgMCAwIDEgMTYyLjA5OTItODMuMjUxMnoiIHAtaWQ9IjI0OTk4IiBmaWxsPSIjOTk5OTk5Ij48L3BhdGg+PC9zdmc+") no-repeat center center;
|
||||
background-size: contain;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
}
|
||||
.title {
|
||||
flex: 1;
|
||||
color: $primary-title-color;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
}
|
||||
.icon-top {
|
||||
padding-left: 8px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI1LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IuWbvuWxgl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiCiAgICAgeT0iMHB4IgogICAgIHZpZXdCb3g9IjAgMCAyNCAyNCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjQgMjQ7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojOEJDRjcwO30KPC9zdHlsZT4wCiAgICA8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjAuNyw4LjFjLTEuNS0xLjUtNC40LTQuNC00LjQtNC40Yy0xLjItMS4yLTIuNS0xLjQtMy40LTAuN2MtMC41LDAuNC0wLjcsMC45LTAuOCwxLjRjLTAuMSwwLjUtMC40LDEtMC44LDEuMwoJbC0wLjEsMC4xYy0yLDEuNS00LjMsMi44LTYuOCwzLjJDMy45LDkuMiwzLjMsOS41LDMsMTBjLTAuNiwwLjktMC40LDIuMSwwLjMsMi45bDMuNCwzLjRjMCwwLDAsMCwwLDBsLTMuMSwzLjEKCWMtMC4zLDAuMy0wLjMsMC44LDAsMS4xYzAuMSwwLjEsMC4zLDAuMiwwLjUsMC4yYzAuMiwwLDAuNC0wLjEsMC41LTAuMmwzLjEtMy4xYzAsMCwwLDAsMCwwbDIuOSwyLjljMS4zLDEuMywyLjUsMS41LDMuNCwwLjkKCWMwLjQtMC4zLDAuNy0wLjcsMC45LTEuMmMwLjYtMi4zLDEuNC00LjYsMi44LTYuNWwwLjUtMC43YzAuMy0wLjQsMC44LTAuOCwxLjMtMC44YzAuNS0wLjEsMS4xLTAuMywxLjQtMC44CglDMjEuNywxMC4yLDIxLjUsOC45LDIwLjcsOC4xeiIvPgo8L3N2Zz4K") no-repeat center center;
|
||||
background-size: contain;
|
||||
}
|
||||
.num {
|
||||
padding-left: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.project-h2 {
|
||||
display: none;
|
||||
margin: 16px 4px;
|
||||
padding: 0 8px 0 24px;
|
||||
cursor: default;
|
||||
> p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
height: 36px;
|
||||
em,
|
||||
span {
|
||||
font-style: normal;
|
||||
font-size: 12px;
|
||||
flex-shrink: 0;
|
||||
padding-right: 6px;
|
||||
}
|
||||
.ivu-progress {
|
||||
margin-right: -18px;
|
||||
.ivu-progress-inner {
|
||||
background-color: #e4e4e4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.active {
|
||||
.project-h1 {
|
||||
background: #F4F5F7;
|
||||
}
|
||||
}
|
||||
&.open-menu {
|
||||
.project-h1 {
|
||||
> em {
|
||||
&:before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
.project-h2 {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&.operate {
|
||||
border-color: $primary-color;
|
||||
}
|
||||
&.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px;
|
||||
.common-loading {
|
||||
margin: 6px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.operate-position {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.project-menu-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 36px 36px 20px;
|
||||
min-height: 200px;
|
||||
|
||||
.empty-icon {
|
||||
background-color: #f4f5f7;
|
||||
padding: 20px;
|
||||
border-radius: 50%;
|
||||
|
||||
.ivu-icon {
|
||||
color: #d1d8dd;
|
||||
font-size: 46px;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
margin-top: 16px;
|
||||
color: #bec6cc;
|
||||
background-color: #f4f5f7;
|
||||
padding: 4px 15px;
|
||||
border-radius: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin: 32px 32px 16px;
|
||||
margin: 32px 20px 16px;
|
||||
border-bottom: 1px solid #F4F4F5;
|
||||
.calendar-titbox {
|
||||
flex: 1;
|
||||
@ -180,6 +180,9 @@
|
||||
padding: 16px 46px 16px 47px;
|
||||
}
|
||||
}
|
||||
.tui-full-calendar-popup-detail-item {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
.calendar-menu {
|
||||
|
||||
18
resources/assets/sass/pages/page-dashboard.scss
vendored
18
resources/assets/sass/pages/page-dashboard.scss
vendored
@ -26,19 +26,23 @@
|
||||
max-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.dashboard-hello,
|
||||
.dashboard-desc ,
|
||||
.dashboard-block ,
|
||||
.dashboard-list .dashboard-title,
|
||||
.dashboard-list .dashboard-ul {
|
||||
width: 660px;
|
||||
max-width: 80%;
|
||||
margin: 0 auto;
|
||||
width: 90%;
|
||||
max-width: 90%;
|
||||
margin: 0 30px;
|
||||
}
|
||||
.dashboard-hello {
|
||||
padding: 6% 12px 0;
|
||||
padding: 32px 12px 0;
|
||||
color: $primary-title-color;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
@ -118,8 +122,8 @@
|
||||
}
|
||||
.dashboard-list {
|
||||
width: 100%;
|
||||
margin-top: 48px;
|
||||
padding-bottom: 6%;
|
||||
margin-top: 22px;
|
||||
padding-bottom: 32px;
|
||||
.dashboard-ref {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
56
resources/assets/sass/pages/page-manage.scss
vendored
56
resources/assets/sass/pages/page-manage.scss
vendored
@ -17,7 +17,7 @@
|
||||
position: relative;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
width: 255px;
|
||||
width: 88px;
|
||||
height: 100%;
|
||||
background: #F4F5F7;
|
||||
display: flex;
|
||||
@ -44,21 +44,20 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
> li {
|
||||
list-style: none;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
color: #6b6e72;
|
||||
color: #999999;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
width: 64px;
|
||||
margin: 5px auto;
|
||||
padding: 0 4%;
|
||||
border-radius: 4px;
|
||||
padding: 8px 4%;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
> i {
|
||||
opacity: 0.3;
|
||||
font-size: 20px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.menu-title {
|
||||
flex: 1;
|
||||
@ -67,14 +66,17 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.menu-badge {
|
||||
margin-left: 12px;
|
||||
transform: scale(0.9);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 35px;
|
||||
}
|
||||
&:first-child {
|
||||
margin-top: 12px;
|
||||
}
|
||||
&.active {
|
||||
background-color: #ffffff;
|
||||
color: #8FCE78;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,11 +246,30 @@
|
||||
}
|
||||
}
|
||||
.manage-box-new-group {
|
||||
width: 80%;
|
||||
width: 60%;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
ul{
|
||||
list-style-type: none;
|
||||
width: 100%;
|
||||
li{
|
||||
margin-top: 12px;
|
||||
color: #999999;
|
||||
.taskfont{
|
||||
font-size: 22px;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
&:hover{
|
||||
background-color: #ffffff;
|
||||
color: #8FCE78;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.manage-box-new {
|
||||
flex: 1;
|
||||
}
|
||||
@ -299,18 +320,18 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 6px 10px;
|
||||
padding: 6px 14px;
|
||||
margin-top: 27px;
|
||||
border-radius: 8px;
|
||||
background-color: #ffffff;
|
||||
cursor: pointer;
|
||||
transition: box-shadow 0.3s;
|
||||
position: relative;
|
||||
&.menu-visible {
|
||||
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.manage-box-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
> span {
|
||||
flex: 1;
|
||||
@ -340,12 +361,17 @@
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
flex: 0 0 auto;
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 19px;
|
||||
> i {
|
||||
font-size: 12px;
|
||||
margin: -1px;
|
||||
}
|
||||
.ivu-badge-dot {
|
||||
margin-right: 4px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
resources/assets/sass/pages/page-project.scss
vendored
30
resources/assets/sass/pages/page-project.scss
vendored
@ -2,6 +2,7 @@
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
background-color: #fafafa;
|
||||
.project-panel {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
@ -16,6 +17,35 @@
|
||||
max-width: 520px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.page-project-empty{
|
||||
flex: 1;
|
||||
height: 90%;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
>div{
|
||||
width: 86px;
|
||||
height: 86px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #F4F5F7;
|
||||
border-radius: 100%;
|
||||
margin-bottom: 16px;
|
||||
.taskfont{
|
||||
color: rgba(157, 167, 175, 0.6);
|
||||
font-size: 46px;
|
||||
}
|
||||
}
|
||||
span{
|
||||
background: #F4F5F7;
|
||||
color: #9DA7AF;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 700px) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
resources/assets/statics/public/images/empty/empty.svg
Normal file
1
resources/assets/statics/public/images/empty/empty.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
Loading…
x
Reference in New Issue
Block a user