19 changed files with 934 additions and 111 deletions
@ -1,5 +1,8 @@ |
|||
import { createStore } from 'vuex'; |
|||
import user from './tall/user'; |
|||
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,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; |
@ -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; |
@ -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, |
|||
}; |
@ -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; |
@ -0,0 +1,8 @@ |
|||
const state = { |
|||
invisibleRoles: [], // 不展示的角色信息
|
|||
visibleRoles: [], // 展示的角色信息
|
|||
roleId: '', // 当前展示查看的角色id
|
|||
members: [], // 项目下所有成员
|
|||
}; |
|||
|
|||
export default state; |
@ -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); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
@ -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> |
|||
|
|||
<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> |
|||
|
@ -1,26 +1,84 @@ |
|||
<template> |
|||
<div class="task-detail"> |
|||
<!-- <div class="task-detail"> |
|||
<div class="task-con">任务详情页</div> |
|||
<!-- <div> |
|||
<div> |
|||
<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> |
|||
|
|||
<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); // 是否显示左栏 |
|||
|
|||
// 验证 获取query中u参数 获取token |
|||
// const route = useRoute(); |
|||
// const router = useRouter(); |
|||
// const userString = sessionStorage.getItem('user'); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.task-detail { |
|||
.ant-layout { |
|||
width: 100%; |
|||
height: 100%; |
|||
padding: 15px 12px; |
|||
} |
|||
|
|||
.task-con { |
|||
width: 100%; |
|||
height: 500px; |
|||
background-color: #fff; |
|||
border-radius: 10px; |
|||
border: 1px solid #cccccc; |
|||
.ant-layout-header { |
|||
height: 48px; |
|||
line-height: 48px; |
|||
padding: 0 16px; |
|||
border-bottom: 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> |
|||
|
@ -1,5 +1,133 @@ |
|||
<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> |
|||
|
|||
<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…
Reference in new issue