Browse Source

feat: "登录、项目列表"

master
xuesinan 4 years ago
parent
commit
42b67f6524
  1. 3
      .eslintrc.js
  2. 92
      src/App.vue
  3. 15
      src/apis/index.js
  4. 74
      src/components/tall/center/ProjectDetail.vue
  5. 25
      src/components/tall/left/Index.vue
  6. 95
      src/components/tall/left/Projects.vue
  7. 48
      src/components/tall/top/TopNavbar.vue
  8. 7
      src/store/index.js
  9. 0
      src/store/tall/projects/index.js
  10. 20
      src/store/tall/role/actions.js
  11. 14
      src/store/tall/role/getters.js
  12. 12
      src/store/tall/role/index.js
  13. 39
      src/store/tall/role/mutations.js
  14. 8
      src/store/tall/role/state.js
  15. 320
      src/store/tall/task/index.js
  16. 12
      src/store/tall/user/index.js
  17. 25
      src/views/detail/Test.vue
  18. 82
      src/views/home/Index.vue
  19. 132
      src/views/user/SignIn.vue

3
.eslintrc.js

@ -12,6 +12,7 @@ module.exports = {
rules: { rules: {
'import/no-unresolved': 0, 'import/no-unresolved': 0,
'import/extensions': 0, 'import/extensions': 0,
'import/no-extraneous-dependencies': 0,
'no-plusplus': 0, 'no-plusplus': 0,
'no-use-before-define': [ 'no-use-before-define': [
'error', 'error',
@ -26,7 +27,7 @@ module.exports = {
'no-unused-expressions': 'off', 'no-unused-expressions': 'off',
'vue/no-mutating-props': 'off', 'vue/no-mutating-props': 'off',
'vue/no-multiple-template-root': 'off', 'vue/no-multiple-template-root': 'off',
"no-shadow": ["error", { "builtinGlobals": false, "hoist": "functions", "allow": [] }], 'no-shadow': ['error', { builtinGlobals: false, hoist: 'functions', allow: [] }],
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-param-reassign': 'off', 'no-param-reassign': 'off',

92
src/App.vue

@ -1,65 +1,75 @@
<template> <template>
<div v-if="!token"></div> <div style="width: 100%; height: 100%">
<router-view></router-view>
</div>
<a-config-provider v-else :locale="locale"> <!-- <a-config-provider v-else :locale="locale"> -->
<a-layout> <!-- <a-layout> -->
<a-layout-header style="background: #fff"> <TopNavbar /> </a-layout-header> <!-- <a-layout-header style="background: #fff"> <TopNavbar /> </a-layout-header> -->
<a-layout> <!-- <a-layout> -->
<!-- 日历页--> <!-- 日历页-->
<a-layout-sider v-show="collapsed" style="background: #fff"><Left /></a-layout-sider> <!-- <a-layout-sider v-show="collapsed" style="background: #fff"><Left /></a-layout-sider> -->
<a-layout> <!-- <a-layout> -->
<a-layout-sider class="project-detail"><ProjectDetail /></a-layout-sider> <!-- <a-layout-sider class="project-detail"><ProjectDetail /></a-layout-sider> -->
<a-layout> <!-- <a-layout> -->
<!-- 导航栏--> <!-- 导航栏-->
<a-layout-header style="background: #fff"> <!-- <a-layout-header style="background: #fff"> -->
<Navbar /> <!-- <Navbar /> -->
</a-layout-header> <!-- </a-layout-header> -->
<!-- 内容区--> <!-- 内容区-->
<a-layout-content><router-view></router-view></a-layout-content> <!-- <a-layout-content><router-view></router-view></a-layout-content> -->
<!-- 脚部--> <!-- 脚部-->
<!-- <a-layout-footer>Footer</a-layout-footer>--> <!-- <a-layout-footer>Footer</a-layout-footer>-->
</a-layout> <!-- </a-layout> -->
</a-layout> <!-- </a-layout> -->
</a-layout> <!-- </a-layout> -->
</a-layout> <!-- </a-layout> -->
</a-config-provider> <!-- </a-config-provider> -->
</template> </template>
<script setup> <script setup>
import { computed } from 'vue'; // import { computed } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import { useRoute, useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import zhCN from 'ant-design-vue/es/locale/zh_CN'; // import zhCN from 'ant-design-vue/es/locale/zh_CN';
import Left from 'components/tall/left/Index.vue'; // import Left from 'components/tall/left/Index.vue';
import Navbar from 'components/tall/top/Navbar.vue'; // import Navbar from 'components/tall/top/Navbar.vue';
import TopNavbar from 'components/tall/top/TopNavbar.vue'; // import TopNavbar from 'components/tall/top/TopNavbar.vue';
import ProjectDetail from 'components/tall/center/ProjectDetail.vue'; // import ProjectDetail from 'components/tall/center/ProjectDetail.vue';
const locale = zhCN; // const locale = zhCN;
const store = useStore(); const store = useStore();
const collapsed = computed(() => store.state.layout.display.left); // // const collapsed = computed(() => store.state.layout.display.left); //
// queryu token // queryu token
const route = useRoute(); // const route = useRoute();
const router = useRouter(); const router = useRouter();
const userString = sessionStorage.getItem('user');
useRouter() if (userString) {
.isReady() const user = JSON.parse(userString);
.then(async () => { store.commit('user/setUser', user);
const u = computed(() => route.query.u); } else {
if (!u.value) {
// urlu,
console.log('缺少参数');
router.push({ path: '/user/signIn' }); router.push({ path: '/user/signIn' });
} else { }
// userId token
await store.dispatch('user/getTokenByUserId', u.value); // useRouter()
} // .isReady()
}); // .then(async () => {
// const u = computed(() => route.query.u);
// if (!u.value) {
// // urlu,
// console.log('');
// router.push({ path: '/user/signIn' });
// } else {
// // userId token
// await store.dispatch('user/getTokenByUserId', u.value);
// }
// });
const token = computed(() => store.getters['user/token']); // const token = computed(() => store.getters['user/token']);
</script> </script>
<style> <style>

15
src/apis/index.js

@ -10,5 +10,18 @@ const tall = `${apiUrl}/gateway/tall3/v3.0`;
// eslint-disable-next-line import/prefer-default-export // eslint-disable-next-line import/prefer-default-export
export const getToken = userId => http.get(`${users}/userId`, { params: { userId } }); export const getToken = userId => http.get(`${users}/userId`, { params: { userId } });
// 登录api
export const signIn = params => http.post(`${users}/signin`, params);
// 获取项目列表 // 获取项目列表
export const getProjects = (startTime, endTime) => http.post(`${tall}/project/query`, { startTime, endTime }); export const getProjects = (startTime, endTime) => http.post(`${tall}/project/query`, { param: { startTime, endTime } });
// 根据项目id查找角色
export const findShowRole = param => http.post(`${tall}/role/show`, param);
// 根据项目id查找所有成员
export const queryChecker = param => http.post(`${tall}/deliver/queryChecker`, param);
export const getGlobal = params => http.post(`${tall}/task/global`, params);
export const getPermanent = params => http.post(`${tall}/task/permanent`, params);

74
src/components/tall/center/ProjectDetail.vue

@ -38,19 +38,19 @@
<div class="task-name">任务名</div> <div class="task-name">任务名</div>
<div class="task-con"> <div class="task-con">
<div> <div>
<a-checkbox @change="onChange"><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox> <a-checkbox><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox>
</div> </div>
<div> <div>
<a-checkbox @change="onChange"><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox> <a-checkbox><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox>
</div> </div>
<div> <div>
<a-checkbox @change="onChange"><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox> <a-checkbox><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox>
</div> </div>
<div> <div>
<a-checkbox @change="onChange"><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox> <a-checkbox><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox>
</div> </div>
<div> <div>
<a-checkbox @change="onChange"><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox> <a-checkbox><span class="child-project-name">子课题负责人1 穿戴式运动捕获单元</span></a-checkbox>
</div> </div>
</div> </div>
<div class="open-icon" @click="openCard"> <div class="open-icon" @click="openCard">
@ -81,7 +81,69 @@
</div> </div>
</template> </template>
<script setup></script> <script setup>
import { computed, watch } from 'vue';
import { useStore } from 'vuex';
// import { findShowRole } from 'apis';
const store = useStore();
// const project = ref(0)
const project = computed(() => store.state.projects.project);
watch(project, (newVal, oldVal) => {
console.log(newVal.p, oldVal.p);
// clearTasksData();
// getGlobalData(); //
// initPlanTasks(); //
});
console.log('project', project.value.p);
//
// const setInitialRoleId = visibleList => {
// if (!visibleList || !visibleList.length) return;
// const index = visibleList.findIndex(item => +item.mine === 1);
// const currentRole = index > 0 ? visibleList[index] : visibleList[0];
// // const storageRoleId = uni.getStorageSync('roleId');
// const currentRoleId = storageRoleId ? storageRoleId : currentRole ? currentRole.id : '';
// store.commit('role/setRoleId', currentRoleId);
// // storage
// // uni.setStorageSync('roleId', '');
// }
// /**
// * id
// * @param {string} projectId
// * @param {object} params
// */
// const getRoles = async params => {
// try {
// let data = await findShowRole(params);
// store.commit('role/setInvisibleRoles', data ? data.invisibleList : []);
// store.commit('role/setVisibleRoles', data ? data.visibleList : []);
// setInitialRoleId(data ? data.visibleList : []);
// } catch (error) {
// throw new Error(error);
// }
// }
// //
// function clearTasksData() {
// //
// // setPermanents([]);
// // setDailyTasks([]);
// // //
// // clearTasks();
// //
// //
// // clearEndFlag();
// }
// //
// function getGlobalData() {
// const { roleId, timeNode, timeUnit, projectId } = this;
// const param = { roleId, timeNode, timeUnit, projectId };
// store.dispatch('task/getGlobal', param);
// }
</script>
<style scoped> <style scoped>
.navbar { .navbar {

25
src/components/tall/left/Index.vue

@ -4,6 +4,7 @@
</template> </template>
<script setup> <script setup>
import { reactive } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { getProjects } from 'apis'; import { getProjects } from 'apis';
@ -11,22 +12,30 @@ import Calendar from './Calendar.vue';
import Projects from './Projects.vue'; import Projects from './Projects.vue';
const store = useStore(); const store = useStore();
const projects = reactive([]);
// //
const getProjectsList = async (startTime, endTime) => { const getProjectsList = async (startTime, endTime) => {
const params = { param: { startTime, endTime } };
try { try {
const res = await getProjects(params); const data = await getProjects(startTime, endTime);
data.forEach(item => {
item.show = false;
});
if (res.err) { data.forEach(item => {
console.error('err: ', res.err);
} else {
res.data.forEach(item => {
item.show = false; item.show = false;
if (item.sonsonProjectList) {
item.sonsonProjectList.forEach(sonItem => {
sonItem.show = false;
}); });
store.commit('projects/setProjects', res.data);
} }
projects.push(item);
});
store.commit('projects/setProjects', projects);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

95
src/components/tall/left/Projects.vue

@ -1,41 +1,40 @@
<template> <template>
<a-divider /> <a-divider />
<div class="project-list">项目列表</div>
<div class="list-flex"> <div class="list-flex">
<div class="item-box"> <div class="item-box" v-for="(item, index) in projects" :key="index">
<div class="one-level h-70 cursor-pointer flex items-center" @click="toDetail()"> <div class="one-level h-70 cursor-pointer flex items-center" @click="toDetail(item)">
<div class="icon"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> <div class="icon"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div>
<div class="detail"> <div class="detail">
<div class="name-box flex items-center"> <div class="name-box flex items-center">
<div class="name truncate">项目名称</div> <div class="name truncate">{{ item.name }}</div>
<div class="precent">50%</div> <div class="precent">50%</div>
</div> </div>
<div class="time">11-21 00:00 11-21 23.59</div> <div class="time">{{ dayjs(item.startTime).format('HH:mm:ss') }} {{ dayjs(item.endTime).format('HH:mm:ss') }}</div>
</div> </div>
<div class="right" @click.stop="openMenu"> <div class="right" @click.stop="openMenu">
<img src="" /> <RightOutlined v-if="!item.show" />
<img src="" /> <DownOutlined v-else />
</div> </div>
</div> </div>
<div class="two-box"> <div class="two-box" v-for="(sonItem, sonIndex) in item.sonProjectList" :key="sonIndex">
<div class="two-flex"> <div class="two-flex">
<div class="two-level h-70 cursor-pointer flex items-center" @click="toDetail()"> <div class="two-level h-70 cursor-pointer flex items-center" @click="toDetail()">
<div class="icon"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div> <div class="icon"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div>
<div class="detail"> <div class="detail">
<div class="name-box flex items-center"> <div class="name-box flex items-center">
<div class="name truncate">项目名称</div> <div class="name truncate">{{ sonItem.name }}</div>
<div class="precent">50%</div> <div class="precent">50%</div>
</div> </div>
<div class="time">11-21 00:00 11-21 23.59</div> <div class="time">{{ dayjs(sonItem.startTime).format('HH:mm:ss') }} {{ dayjs(sonItem.endTime).format('HH:mm:ss') }}</div>
</div> </div>
<div class="right" @click.stop="openMenu"> <div class="right" @click.stop="openMenu">
<img src="" /> <RightOutlined v-if="!sonItem.show" />
<img src="" /> <DownOutlined v-else />
</div> </div>
</div> </div>
@ -59,17 +58,74 @@
</template> </template>
<script setup> <script setup>
// import { useStore } from 'vuex'; import { reactive } from 'vue';
import { useStore } from 'vuex';
// const store = useStore(); import dayjs from 'dayjs';
import { getProjects } from 'apis';
function toDetail() {} import { RightOutlined, DownOutlined } from '@ant-design/icons-vue';
const store = useStore();
const projects = reactive([]);
// const projectList = computed(() => store.state.projects.projects);
// watch( projectList, ( newVal, oldVal ) => { console.log( newVal + ":===" + oldVal ) })
// console.log('projectList', projectList)
//
const getProjectsList = async (startTime, endTime) => {
try {
const data = await getProjects(startTime, endTime);
data.forEach(item => {
item.show = false;
if (item.sonsonProjectList) {
item.sonsonProjectList.forEach(sonItem => {
sonItem.show = false;
});
}
projects.push(item);
});
store.commit('projects/setProjects', data);
} catch (error) {
console.log(error);
}
};
getProjectsList(dayjs().startOf('day').format('x'), dayjs().endOf('day').format('x'));
function toDetail(project) {
//
// const { name, id, url } = project;
// url && (uni.$t.domain = url);
// this.$u.route('pages/project-webview/project-webview', {
// u: this.userId,
// p: id,
// pname: name,
// url: encodeURIComponent(url),
// });
const obj = {
u: project.userId,
p: project.id,
pname: project.name,
url: project.url,
};
store.commit('projects/setProject', obj);
}
</script> </script>
<script> <script>
export default { name: 'Projects' }; export default { name: 'Projects' };
</script> </script>
<style scoped> <style scoped>
.list-flex {
height: calc(100vh - 48px - 272px - 56px - 16px - 2px);
overflow-y: auto;
}
.ant-divider-horizontal { .ant-divider-horizontal {
height: 16px; height: 16px;
background: #eeeeee; background: #eeeeee;
@ -115,6 +171,7 @@ export default { name: 'Projects' };
line-height: 1; line-height: 1;
font-weight: 600; font-weight: 600;
max-width: calc(100% - 56px); max-width: calc(100% - 56px);
color: #333333;
} }
.precent { .precent {
@ -138,4 +195,8 @@ export default { name: 'Projects' };
width: 14px; width: 14px;
margin-left: 30px; margin-left: 30px;
} }
::-webkit-scrollbar {
width: 0 !important;
}
</style> </style>

48
src/components/tall/top/TopNavbar.vue

@ -1,10 +1,18 @@
<template> <template>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<h1 class="">实验平台</h1> <h1 class="">
<div> <span>实验平台</span>
<menu-unfold-outlined v-if="collapsed" @click="toggleCollapse" /> <menu-unfold-outlined v-if="collapsed" @click="toggleCollapse" />
<menu-fold-outlined v-else class="trigger" @click="toggleCollapse" /> <menu-fold-outlined v-else class="trigger" @click="toggleCollapse" />
用户信息 </h1>
<div class="user-info relative flex items-center cursor-pointer">
<a-image :width="30" src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png" />
<div class="mr-3 ml-3">{{ account }}</div>
<CaretDownOutlined />
<div class="user-action absolute">
<div @click="signOut">退出登录</div>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -12,22 +20,52 @@
<script setup> <script setup>
import { computed } from 'vue'; import { computed } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue'; import { MenuUnfoldOutlined, MenuFoldOutlined, CaretDownOutlined } from '@ant-design/icons-vue';
const store = useStore(); const store = useStore();
const router = useRouter();
const collapsed = computed(() => store.state.layout.display.left); // const collapsed = computed(() => store.state.layout.display.left); //
const account = computed(() => store.getters['user/account']);
// toggle left window display // toggle left window display
function toggleCollapse() { function toggleCollapse() {
store.commit('layout/setDisplay', { prop: 'left', show: !collapsed.value }); store.commit('layout/setDisplay', { prop: 'left', show: !collapsed.value });
} }
// 退
function signOut() {
store.commit('user/setUser', null);
router.push({ path: '/user/signin' });
}
</script> </script>
<style scoped> <style scoped>
h1 { h1 {
margin: 0;
}
h1 span {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
margin: 0; margin-right: 10px;
}
.user-info {
height: 48px;
}
.user-action {
display: none;
top: 48px;
right: 0;
width: 150px;
text-align: center;
box-shadow: 0px 0 6px 0px rgba(0, 0, 0, 0.3);
}
.user-info:hover .user-action {
display: block;
} }
</style> </style>

7
src/store/index.js

@ -1,5 +1,8 @@
import { createStore } from 'vuex'; import { createStore } from 'vuex';
import user from './tall/user';
import layout from './tall/layout'; import layout from './tall/layout';
import projects from './tall/projects';
import role from './tall/role';
import task from './tall/task';
import user from './tall/user';
export default createStore({ modules: { user, layout } }); export default createStore({ modules: { user, projects, role, task, layout } });

0
src/store/tall/projects/projects.js → src/store/tall/projects/index.js

20
src/store/tall/role/actions.js

@ -0,0 +1,20 @@
import { queryChecker } from 'apis';
const actions = {
/**
* 根据项目id查找所有成员信息
* @param {*} commit
* @param {object} params
*/
async getAllMembers({ commit }, params) {
try {
const data = await queryChecker(params);
commit('setMembers', data);
return data;
} catch (error) {
throw new Error(error);
}
},
};
export default actions;

14
src/store/tall/role/getters.js

@ -0,0 +1,14 @@
const getters = {
// 是不是负责人
isMine({ roleId, invisibleRoles, visibleRoles }) {
console.log(roleId, invisibleRoles, visibleRoles);
// if (!visibleRoles || !visibleRoles.length) return false;
// const visible = visibleRoles.find(visible => visible.id === roleId);
// if (visible) return visible.mine;
// const invisible = invisibleRoles.find(invisible => invisible.id === roleId);
// if (invisible) return visible.mine;
return false;
},
};
export default getters;

12
src/store/tall/role/index.js

@ -0,0 +1,12 @@
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};

39
src/store/tall/role/mutations.js

@ -0,0 +1,39 @@
const mutations = {
/**
* 设置不展示的角色信息
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setInvisibleRoles(state, data) {
state.invisibleRoles = data || [];
},
/**
* 设置展示的角色信息
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setVisibleRoles(state, data) {
state.visibleRoles = data || [];
},
/**
* 设置当前角色信息
* @param {Object} state
* @param {string} roleId 当前正在展示的角色的id
*/
setRoleId(state, roleId) {
state.roleId = roleId;
},
/**
* 设置项目下所有成员信息
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setMembers(state, data) {
state.members = data || [];
},
};
export default mutations;

8
src/store/tall/role/state.js

@ -0,0 +1,8 @@
const state = {
invisibleRoles: [], // 不展示的角色信息
visibleRoles: [], // 展示的角色信息
roleId: '', // 当前展示查看的角色id
members: [], // 项目下所有成员
};
export default state;

320
src/store/tall/task/index.js

@ -0,0 +1,320 @@
import { getGlobal, getPermanent } from 'apis';
export default {
namespaced: true,
state: {
scrollTop: 0,
scrollToTaskId: '', // 时间轴自动滚动的位置
isShrink: false, // true: 收起, false:展开
tip: {
taskId: '', // 当前正在修改状态的任务的id
show: false,
status: 0, // 所点击任务的当前状态码
text: '',
left: 0, // 鼠标点击位置距离左边的距离
top: 0, // 鼠标点击位置距离上边的距离
},
timeNode: new Date().getTime(), // 时间基准点
timeUnit: 4, // 时间颗粒度
topEnd: false, // 时间轴向上查任务到顶了
bottomEnd: false, // 时间轴向下查任务到底了
permanents: [], // 永久日常任务
dailyTasks: [], // 日常任务
tasks: [], // 所有的定期任务
showSkeleton: false, // 定期任务骨架屏
newProjectInfo: {},
showScrollTo: false, // 是否可以设置时间轴自动滚动的位置
},
getters: {
// 所有的日常任务 永久 + 可变 日常任务
globals({ dailyTasks, permanents }) {
return [...permanents, ...dailyTasks];
},
// unitConfig({ timeUnit }) {
// const target = uni.$t.timeConfig.timeUnits.find(item => item.id === timeUnit);
// return target;
// },
// 计算任务开始时间的格式
startTimeFormat(state, { unitConfig }) {
return unitConfig.format || 'D日 HH:mm';
},
// 计算颗粒度 对应的 dayjs add 的单位
timeGranularity(state, { unitConfig }) {
return unitConfig.granularity;
},
},
mutations: {
/**
* 记录时间轴向上滚动的距离
* @param { object } state
* @param { number } num
*/
setScrollTop(state, num) {
state.scrollTop = num;
},
/**
* 记录时间轴向上滚动的距离
* @param { object } state
* @param {string} taskId
*/
setScrollToTaskId(state, taskId) {
state.scrollToTaskId = taskId;
},
/**
* 设置日常任务当前是否应该处于收缩状态
* @param { object } state
* @param { boolean } data
*/
setShrink(state, data) {
state.isShrink = data;
},
/**
* 设置tip的值
* @param {object} state
* @param {object} data
*/
setTip(state, data) {
if (!data) return;
state.tip = { ...data };
},
/**
* 是否显示tips
* @param { object } state
* @param { boolean } show
*/
setTipShow(state, show) {
state.tip.show = show;
},
/**
* 是否显示tips
* @param { object } state
* @param { number } status
*/
setStatus(state, status) {
state.tip.status = status;
},
/**
* 设置时间基准点
* @param { object } state
* @param { number } data
*/
setTimeNode(state, data) {
state.timeNode = data;
},
/**
* 设置时间颗粒度
* @param { object } state
* @param { number } data
*/
setTimeUnit(state, data) {
state.timeUnit = data;
},
/**
* 设置向上查到的定期任务数据
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setUpTasks(state, data) {
if (!state.tasks.length) {
state.tasks = [...data]; // 原来没有数据
} else {
state.tasks = [...data, ...state.tasks];
const arr = [];
let flag = false;
state.tasks.forEach(task => {
arr.forEach(item => {
if (task.id === item.id) {
flag = true;
}
});
if (!flag) {
arr.push(task);
}
});
state.tasks = [...arr];
// state.tasks = [...data.concat(state.tasks)];
}
},
/**
* 设置向下查到的定期任务数据
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setDownTasks(state, data) {
if (!state.tasks && !state.tasks.length) {
state.tasks = [...data];
} else {
state.tasks = [...state.tasks, ...data];
const arr = [];
let flag = false;
state.tasks.forEach(task => {
arr.forEach(item => {
if (task.id === item.id) {
flag = true;
}
});
if (!flag) {
arr.push(task);
}
});
state.tasks = [...arr];
// state.tasks = [...state.tasks.concat(data)];
}
},
/**
* 添加任务后更新tasks
* @param {Object} state
* @param {Array} data 新添加的task
*/
updateTasks(state, data) {
state.tasks = [...data];
},
/**
* 设置添加任务的位置
* @param {*} state
* @param {*} data
*/
setAddPosition(state, data) {
console.log('data: ', data);
},
/**
* 设置日常任务数据
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setDailyTasks(state, data) {
state.dailyTasks = data || [];
},
/**
* 设置永久固定任务
* @param {object} state
* @param {array} tasks 服务端查询到的永久日常任务书籍
*/
setPermanents(state, tasks) {
state.permanents = tasks || [];
},
/**
* 设置时间轴是否继续向上查任务
* @param {Object} state
* @param {Boolean} show
*/
setTopEnd(state, show) {
state.topEnd = show;
},
/**
* 设置时间轴是否继续向下查任务
* @param {Object} state
* @param {Boolean} show
*/
setBottomEnd(state, show) {
state.bottomEnd = show;
},
// 清空标志位 如切换角色等使用
clearEndFlag(state) {
state.topEnd = false;
state.bottomEnd = false;
},
// 清空定期任务
clearTasks(state) {
state.tasks = [];
},
/**
* 收到消息设置任务状态
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setTaskStatus(state, data) {
const item = state.tasks.find(i => i.id === data.id);
item.process = data.taskStatus;
},
/**
* 收到打开新项目消息状态
* @param {Object} state
* @param {Array} data 服务端返回的模板数组
*/
setNewProjectInfo(state, data) {
state.newProjectInfo = data;
},
/**
* 设置骨架屏是否显示
* @param {Object} state
* @param {Boolean} show
*/
setShowSkeleton(state, show) {
state.showSkeleton = show;
},
/**
* 是否设置时间轴自动滚动的位置
* @param {Object} state
* @param {Boolean} show
*/
setShowScrollTo(state, show) {
state.showScrollTo = show;
},
},
actions: {
/**
* 根据角色查找永久的日常任务
* @param {*} commit
* @param {string} roleId 角色id
*/
async getPermanent({ commit }, param) {
try {
const data = await getPermanent(param);
commit('setPermanents', data);
return data;
} catch (error) {
throw new Error(error);
}
},
/**
* 根据时间和角色查找日常任务
* @param {*} commit
* @param {object} param 请求参数 roleId, timeNode, timeUnit
*/
async getGlobal({ commit }, param) {
try {
const data = await getGlobal(param);
commit('setDailyTasks', data);
return data;
} catch (error) {
throw new Error(error);
}
},
},
};

12
src/store/tall/user/index.js

@ -14,6 +14,10 @@ export default {
if (!user) return null; if (!user) return null;
return user.id; return user.id;
}, },
account({ user }) {
if (!user) return null;
return user.account;
},
}, },
mutations: { mutations: {
@ -25,11 +29,11 @@ export default {
setUser(state, user) { setUser(state, user) {
state.user = user; state.user = user;
if (user) { if (user) {
localStorage.setItem('token', user.token); sessionStorage.setItem('token', user.token);
localStorage.setItem('user', JSON.stringify(user)); sessionStorage.setItem('user', JSON.stringify(user));
} else { } else {
localStorage.removeItem('token'); sessionStorage.removeItem('token');
localStorage.removeItem('user'); sessionStorage.removeItem('user');
} }
}, },
}, },

25
src/views/detail/Test.vue

@ -1,3 +1,26 @@
<template>测试</template> <template>
<div class="task-detail">
<div class="task-con">任务详情页</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script setup></script> <script setup></script>
<style scoped>
.task-detail {
width: 100%;
height: 100%;
padding: 15px 12px;
}
.task-con {
width: 100%;
height: 500px;
background-color: #fff;
border-radius: 10px;
border: 1px solid #cccccc;
}
</style>

82
src/views/home/Index.vue

@ -1,26 +1,84 @@
<template> <template>
<div class="task-detail"> <!-- <div class="task-detail">
<div class="task-con">任务详情页</div> <div class="task-con">任务详情页</div>
<!-- <div> <div>
<router-view></router-view> <router-view></router-view>
</div> -->
</div> </div>
</div> -->
<a-config-provider :locale="locale">
<a-layout>
<a-layout-header style="background: #fff"> <TopNavbar /> </a-layout-header>
<a-layout>
<!-- 日历页-->
<a-layout-sider v-show="collapsed" style="background: #fff"><Left /></a-layout-sider>
<a-layout>
<a-layout-sider class="project-detail"><ProjectDetail /></a-layout-sider>
<a-layout>
<!-- 导航栏-->
<a-layout-header style="background: #fff">
<Navbar />
</a-layout-header>
<!-- 内容区-->
<a-layout-content><router-view></router-view></a-layout-content>
<!-- 脚部-->
<!-- <a-layout-footer>Footer</a-layout-footer>-->
</a-layout>
</a-layout>
</a-layout>
</a-layout>
</a-config-provider>
</template> </template>
<script setup></script> <script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';
// import { useRoute, useRouter } from 'vue-router';
import zhCN from 'ant-design-vue/es/locale/zh_CN';
import Left from 'components/tall/left/Index.vue';
import Navbar from 'components/tall/top/Navbar.vue';
import TopNavbar from 'components/tall/top/TopNavbar.vue';
import ProjectDetail from 'components/tall/center/ProjectDetail.vue';
const locale = zhCN;
const store = useStore();
const collapsed = computed(() => store.state.layout.display.left); //
// queryu token
// const route = useRoute();
// const router = useRouter();
// const userString = sessionStorage.getItem('user');
</script>
<style scoped> <style scoped>
.task-detail { .ant-layout {
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 15px 12px;
} }
.task-con { .ant-layout-header {
width: 100%; height: 48px;
height: 500px; line-height: 48px;
background-color: #fff; padding: 0 16px;
border-radius: 10px; border-bottom: 1px solid #cccccc;
border: 1px solid #cccccc; }
.ant-layout-sider {
width: 300px !important;
max-width: 300px !important;
min-width: 300px !important;
border-right: 1px solid #cccccc;
flex: 0 0 300px !important;
}
.project-detail {
width: 400px !important;
max-width: 400px !important;
min-width: 400px !important;
border-right: 1px solid #cccccc;
flex: 0 0 400px !important;
background: #fff;
} }
</style> </style>

132
src/views/user/SignIn.vue

@ -1,5 +1,133 @@
<template> <template>
<div>登录</div> <div class="login-box relative flex justify-between" style="width: 100%; height: 100%">
<div class="login-wrap absolute right-0">
<div class="login-form relative">
<h1>山西大学实验管理平台</h1>
<!-- 用户名密码输入 -->
<a-form ref="signInFormRef" :model="signInForm" :rules="rules">
<a-form-item name="username">
<label style="font-size: 16px"><span style="color: #ff5353; margin-right: 5px">*</span>用户名</label>
<a-input :model:value="signInForm.username" placeholder="请输入用户名" />
</a-form-item>
<a-form-item name="password">
<label style="font-size: 16px"><span style="color: #ff5353; margin-right: 5px">*</span>密码</label>
<a-input :model:value="signInForm.password" type="password" placeholder="请输入密码" />
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit" @click="handleSingIn">登录</a-button>
</a-form-item>
</a-form>
</div>
</div>
</div>
</template> </template>
<script setup></script> <script setup>
import { reactive, ref } from 'vue';
import { signIn } from 'apis';
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
const store = useStore();
const router = useRouter();
const signInFormRef = ref(null);
const signInForm = reactive({
username: '',
password: '',
});
const rules = reactive({
username: [
{
required: true,
message: '请输入账号',
trigger: 'blur',
},
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'blur',
},
],
});
//
function handleSingIn() {
signInFormRef.value
.validate()
.then(async () => {
if (signInForm.username && signInForm.password) {
try {
const params = {
client: 1,
data: {
identifier: signInForm.username,
credential: signInForm.password,
},
type: 3,
};
const resData = await signIn(params);
store.commit('user/setUser', resData);
// ElMessage.success(' ');
console.log('登录成功, 欢迎回来');
setTimeout(() => {
//
router.push({ path: '/' });
}, 1000);
} catch (error) {
throw new Error(error);
}
}
})
.catch(error => {
console.log('error', error);
});
}
</script>
<style scoped>
.login-box {
width: 100%;
height: 100%;
background: url('https://www.tall.wiki/staticrec/icon/bg.png') no-repeat;
background-size: cover;
}
.login-wrap {
background: #e9f6ff;
width: 446px;
height: 100%;
-moz-box-shadow: -5px 0px 25px 0px rgba(24, 144, 255, 0.12);
-webkit-box-shadow: -5px 0px 25px 0px rgba(24, 144, 255, 0.12);
box-shadow: -5px 0px 25px 0px rgba(24, 144, 255, 0.12);
}
.login-form {
width: 375px;
margin: 0 auto;
top: 50%;
transform: translateY(-50%);
}
h1 {
margin-bottom: 40px;
font-size: 28px;
font-weight: 600;
}
.ant-input {
height: 45px;
margin-top: 15px;
border-radius: 6px;
}
.ant-btn {
margin-top: 32px;
width: 100%;
height: 45px;
border-radius: 6px;
font-size: 18px;
}
</style>

Loading…
Cancel
Save