%2
z1j}FyDN@Bk-4L}96%<89&?NfFfw#-d?7V$%=DnSrS?9oGnBks#zwe%N@A=Lf(cz{J
z$4{5QL`Se2fo=o}?!e?sA=?Xpv%r_Yyn>rl)cpx?4cH;+QSD@-B4B$i@E5SS=*lJg
z-vic23PK}RkH86Fcgc&FHQgymRoLng7y?$5wBk#^z>JdS`&-h=tO&dUrj@i{oTJ#J
z?Iq3kTGI4Z5?G%Qh(lP0wUoe+q*a01_AQ_)^i8s9DS^F`jwJ;40Y{qzUFp^`0{;OE
zB|T0E%m?lRQwx%48G)ZAZK(un`xjtSrx4g6=}HZOZ-GngK;SL#9C()UM7cjGDenIf
zv;9H*o=B6~K;<(h`93STwbFRzN}Ikvh91rC}Jmskglx_$LG4`3SG1H;oXn{ULAx*qY(jBk6Y9n5+ma15%wU
zCXG~zl#0~Kv_!JUjTC1s%a%*J(=34yVIj!!*eIo#=487O#oJs8+5R*+#PONOu1fkk
z&p_K(fv@t61)_oJl@ygc`w%DL{Q~%*!LDpT(xE({Y!4(gA!{T+n)o`o`&s_^k5i_?bx^%z$Xoo7&ihJ
zC2bBciDc*p4hN|OV1PXU3=WgDeG&MsT?q6`I$^sPI0vjv0rn@bP0|h9L2|HN2=pZd
zDH@k48K9zqM|1OIa?3TsVO&z^Um)^(X(LFI0vYd~K5D>kTnIF!K6
zZcFN^1Xiz*odkBZBl?i`lB%$E+RNQ&Y^oG*T{+#+uh-i&by8tX&VOh+DGJ>POmwum
f5$Hys;10Y4ol`SFLHS^500000NkvXXu0mjf+t!T!
diff --git a/src/static/logo.png b/src/static/logo.png
deleted file mode 100644
index b5771e209bb677e2ebd5ff766ad5ee11790f305a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 4023
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
SYs}WS&%*SCNx89m_ 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;
diff --git a/src/store/role/mutations.js b/src/store/role/mutations.js
index 7593f1b..83bd215 100644
--- a/src/store/role/mutations.js
+++ b/src/store/role/mutations.js
@@ -25,6 +25,15 @@ const mutations = {
setRoleId(state, roleId) {
state.roleId = roleId;
},
+
+ /**
+ * 设置项目下所有成员信息
+ * @param {Object} state
+ * @param {Array} data 服务端返回的模板数组
+ */
+ setMembers(state, data) {
+ state.members = data || [];
+ },
};
export default mutations;
diff --git a/src/store/role/state.js b/src/store/role/state.js
index 31b5774..1117de7 100644
--- a/src/store/role/state.js
+++ b/src/store/role/state.js
@@ -2,6 +2,7 @@ const state = {
invisibleRoles: [], // 不展示的角色信息
visibleRoles: [], // 展示的角色信息
roleId: '', // 当前展示查看的角色id
+ members: [], // 项目下所有成员
};
export default state;
diff --git a/src/store/task/actions.js b/src/store/task/actions.js
index b8dfbfb..40cdb31 100644
--- a/src/store/task/actions.js
+++ b/src/store/task/actions.js
@@ -4,13 +4,14 @@ const actions = {
* @param {*} commit
* @param {string} roleId 角色id
*/
- async getPermanent({ commit }, roleId) {
- try {
- const data = await uni.$u.api.getPermanent({ roleId });
- commit('setPermanents', data);
- } catch (error) {
- console.log('task actions getPermanent error: ', error);
- }
+ getPermanent({ commit }, param) {
+ uni.$t.$q.getPermanent(param, (err, data) => {
+ if (err) {
+ console.error('err: ', err);
+ } else {
+ commit('setPermanents', data);
+ }
+ });
},
/**
@@ -18,27 +19,14 @@ const actions = {
* @param {*} commit
* @param {object} param 请求参数 roleId, timeNode, timeUnit
*/
- async getGlobal({ commit }, param) {
- try {
- const data = await uni.$u.api.getGlobal(param);
- commit('setDailyTasks', data);
- } catch (error) {
- console.log('task actions getGlobal error: ', error);
- }
- },
-
- /**
- * 根据时间基准点和角色查找定期任务
- * @param {object} param 查询参数
- * @param {number} param.queryType 必填 0 -> 向上 1 -> 向下
- */
- // eslint-disable-next-line
- async getRegulars({ commit }, param) {
- try {
- return await uni.$u.api.getRegularTask(param);
- } catch (error) {
- throw error || '获取定期任务失败';
- }
+ getGlobal({ commit }, param) {
+ uni.$t.$q.getGlobal(param, (err, data) => {
+ if (err) {
+ console.error('err: ', err);
+ } else {
+ commit('setDailyTasks', data);
+ }
+ });
},
};
diff --git a/src/store/task/mutations.js b/src/store/task/mutations.js
index e644faa..457352d 100644
--- a/src/store/task/mutations.js
+++ b/src/store/task/mutations.js
@@ -11,10 +11,10 @@ const mutations = {
/**
* 记录时间轴向上滚动的距离
* @param { object } state
- * @param { string } data
+ * @param {string} taskId
*/
- setViewId(state, data) {
- state.viewId = data;
+ setScrollToTaskId(state, taskId) {
+ state.scrollToTaskId = taskId;
},
/**
@@ -79,9 +79,10 @@ const mutations = {
*/
setUpTasks(state, data) {
if (!state.tasks.length) {
- state.tasks = [...data];
+ state.tasks = [...data]; // 原来没有数据
} else {
- state.tasks = [...data.concat(state.tasks)];
+ state.tasks = [...data, ...state.tasks];
+ // state.tasks = [...data.concat(state.tasks)];
}
},
@@ -94,7 +95,8 @@ const mutations = {
if (!state.tasks && !state.tasks.length) {
state.tasks = [...data];
} else {
- state.tasks = [...state.tasks.concat(data)];
+ state.tasks = [...state.tasks, ...data];
+ // state.tasks = [...state.tasks.concat(data)];
}
},
diff --git a/src/store/task/state.js b/src/store/task/state.js
index e8397e0..dedff66 100644
--- a/src/store/task/state.js
+++ b/src/store/task/state.js
@@ -1,6 +1,6 @@
const state = {
scrollTop: 0,
- viewId: '', // 时间轴自动滚动的位置
+ scrollToTaskId: '', // 时间轴自动滚动的位置
isShrink: false, // true: 收起, false:展开
tip: {
taskId: '', // 当前正在修改状态的任务的id
@@ -10,21 +10,13 @@ const state = {
left: 0, // 鼠标点击位置距离左边的距离
top: 0, // 鼠标点击位置距离上边的距离
},
- // client: {
- // left: 0, // 鼠标点击位置距离左边的距离
- // top: 0, // 鼠标点击位置距离上边的距离
- // },
- // showTips: false,
- // status: 0, // 点击了时间轴上的哪种样式,默认点击了开始
- // tipsContent: '', // 提示框内的内容,需要传入
timeNode: new Date().getTime(), // 时间基准点
timeUnit: 4, // 时间颗粒度
topEnd: false, // 时间轴向上查任务到顶了
bottomEnd: false, // 时间轴向下查任务到底了
permanents: [], // 永久日常任务
dailyTasks: [], // 日常任务
- // 定期任务
- tasks: [],
+ tasks: [], // 所有的定期任务
showSkeleton: false, // 定期任务骨架屏
};
diff --git a/src/store/user/actions.js b/src/store/user/actions.js
index 6a3acee..cdb2ca0 100644
--- a/src/store/user/actions.js
+++ b/src/store/user/actions.js
@@ -6,10 +6,10 @@ const actions = {
*/
async getToken({ commit }, userId) {
try {
- const res = await uni.$u.api.getToken(userId);
- commit('setToken', res.token);
- commit('setUser', res);
- return res;
+ const data = await uni.$u.api.getToken(userId);
+ commit('setToken', data.token);
+ commit('setUser', data);
+ return data;
} catch (error) {
uni.$t.ui.showToast(error.msg || '获取个人信息失败');
}
diff --git a/src/store/user/mutations.js b/src/store/user/mutations.js
index 49a8bf3..6073c99 100644
--- a/src/store/user/mutations.js
+++ b/src/store/user/mutations.js
@@ -17,7 +17,7 @@ const mutations = {
setUser(state, user) {
if (!user) return;
state.user = { ...user };
- uni.setStorageSync('user', JSON.stringify(user));
+ uni.$t.storage.setStorageSync('user', JSON.stringify(user));
},
};
diff --git a/src/test/util/task.test.js b/src/test/util/task.test.js
new file mode 100644
index 0000000..75ee94a
--- /dev/null
+++ b/src/test/util/task.test.js
@@ -0,0 +1,24 @@
+import { computeFillPlaceholderTaskCount } from '../../utils/task';
+
+describe('computeFillPlaceholderTaskCount', () => {
+ // 2021/8/17 ~ 2021/8/21
+ const tasks = [
+ { id: '99724910037144221455', panel: {}, plugins: [], process: 4, planStart: 1629169800242 },
+ { id: '65053357415671253512', panel: {}, plugins: [], process: 4, planStart: 1629256200242 },
+ { id: '38735454515347179194', panel: {}, plugins: [], process: 4, planStart: 1629342600242 },
+ { id: '49602681534756706607', panel: {}, plugins: [], process: 4, planStart: 1629429000242 },
+ { id: '98860265376222512018', panel: {}, plugins: [], process: 4, planStart: 1629515400242 },
+ { id: '44419041575700334936', panel: {}, plugins: [], process: 4, planStart: 1629601800242 },
+ ];
+ const timeGranularity = 'day';
+
+ it('超出上限 补齐', () => {
+ const data = [{ planStart: `${new Date('2021/8/10').getTime()}` }, { planStart: `${new Date('2021/8/11').getTime()}` }];
+ expect(computeFillPlaceholderTaskCount({ tasks, data, timeGranularity }).prev.toString()).toMatch(/(7|8)/);
+ });
+
+ it('超出下限 补齐', () => {
+ const data = [{ planStart: `${new Date('2021/8/10').getTime()}` }, { planStart: `${new Date('2021/8/22').getTime()}` }];
+ expect(computeFillPlaceholderTaskCount({ tasks, data, timeGranularity }).next.toString()).toMatch(/(1|2)/);
+ });
+});
diff --git a/src/utils/cache.js b/src/utils/cache.js
new file mode 100644
index 0000000..034580d
--- /dev/null
+++ b/src/utils/cache.js
@@ -0,0 +1,344 @@
+export const filter = {
+ /**
+ * 角色 过滤获取到的数据 根据开始截止时间
+ * @param {object} data 缓存拿到的数据
+ * @returns
+ */
+ roles(data) {
+ if (!data || !data.length) return [];
+ return data;
+ },
+
+ /**
+ * 定期任务 过滤获取到的数据 根据开始截止时间
+ * @param {object} data 缓存拿到的数据
+ * @param {number} timeNode 时间基准点 ms
+ * @param {number} queryNum 颗粒度数量
+ * @param {number} timeUnit 时间颗粒度
+ * @param {number} queryType 0向上查找 1向下查找(默认) 下查包含自己,上查不包含
+ * @returns
+ */
+ planTask(data, timeNode, queryNum, timeUnit, queryType) {
+ if (!data || !data.length) return [];
+ if (queryType === 0) {
+ // 计算颗粒度 对应的 dayjs add 的单位
+ let target = uni.$t.timeConfig.timeUnits.find(item => item.id === timeUnit);
+ // TODO: 缺少通过时间颗粒度筛选数据 任务没有返回时间颗粒度标签
+ let start = uni.$t.time.add(+timeNode, -queryNum, target.granularity).valueOf();
+ let arr = [];
+ arr = data.filter(item => start <= +item.planStart && +timeNode > +item.planEnd);
+
+ if (!arr || !arr.length) {
+ // 开始时间往前推
+ let resultS = [];
+ let againStart = uni.$t.time.add(start, -1, target.granularity).valueOf();
+ let againArr = data.filter(item => againStart >= +item.planStart);
+ if (againArr && againArr.length) {
+ let sTime = uni.$t.time.setTimestampToStr(+againArr[0].planStart);
+ data.forEach(item => {
+ if (uni.$t.time.isSame(uni.$moment(sTime.date).valueOf(), +item.planStart, target.granularity)) {
+ resultS.push(item);
+ }
+ });
+ }
+ return resultS;
+ } else {
+ return arr;
+ }
+ } else {
+ // 计算颗粒度 对应的 dayjs add 的单位
+ let target = uni.$t.timeConfig.timeUnits.find(item => item.id === timeUnit);
+ // TODO: 缺少通过时间颗粒度筛选数据 任务没有返回时间颗粒度标签
+ let end = uni.$t.time.add(timeNode, +queryNum - 1, target.granularity).valueOf();
+ let arr = [];
+ arr = data.filter(item => end >= +item.planEnd && +timeNode <= +item.planStart);
+
+ if (!arr || !arr.length) {
+ // 结束时间往后推
+ let resultE = [];
+ let againEnd = uni.$t.time.add(end, 1, target.granularity).valueOf();
+ let againEndArr = data.filter(item => againEnd <= +item.planStart);
+ if (againEndArr) {
+ let eTime = uni.$t.time.setTimestampToStr(+againEndArr[againEndArr.length - 1].planStart);
+ data.forEach(item => {
+ if (uni.$t.time.isSame(uni.$moment(eTime.date).valueOf(), +item.planEnd, target.granularity)) {
+ resultE.push(item);
+ }
+ });
+ }
+ return resultE;
+ } else {
+ return arr;
+ }
+ }
+ },
+
+ /**
+ * 永久日常任务 过滤获取到的数据 根据开始截止时间
+ * @param {object} data 缓存拿到的数据
+ * @returns
+ */
+ fixedTasks(data) {
+ if (!data || !data.length) return [];
+ return data;
+ },
+
+ /**
+ * 日常任务 过滤获取到的数据 根据开始截止时间
+ * @param {object} data 缓存拿到的数据
+ * @param {number} timeNode 时间基准点 ms
+ * @returns
+ */
+ dailyTask(data, timeNode) {
+ if (!data || !data.length) return [];
+ // TODO: 缺少通过时间颗粒度筛选数据 任务没有返回时间颗粒度标签
+ return data.filter(item => timeNode <= +item.endTime && timeNode >= +item.startTime);
+ },
+
+ /**
+ * 插件 过滤获取到的数据 根据插件id
+ * @param {object} data 缓存拿到的数据
+ * @returns
+ */
+ plugin(data) {
+ if (!data || !data.id) return null;
+ return data;
+ },
+};
+
+export default {
+ /**
+ * 当前显示的角色信息 获取
+ * @param {object} params
+ * @returns
+ */
+ async getShowRole(projectId) {
+ try {
+ const data = await uni.$t.storage.getStorage(`roles_${projectId}`);
+ return filter.roles(JSON.parse(data));
+ } catch (error) {
+ return null;
+ }
+ },
+
+ /**
+ * 当前显示的角色信息 存
+ * @param {array} data
+ */
+ putShowRole(projectId, data) {
+ try {
+ if (!data || !data.visibleList || !data.visibleList.length) return; // 服务端没数据不做操作
+ let value = uni.$t.storage.getStorageSync(`roles_${projectId}`);
+ let locals = value ? JSON.parse(value) : null;
+ if (!locals || !locals.length) {
+ // 本地没数据
+ locals = data || null;
+ } else {
+ // 本地有数据
+ data.invisibleList.forEach(item => {
+ let invisibleListLocalData = locals.invisibleList.find(local => item.id === local.id);
+ if (invisibleListLocalData) {
+ // 有相同数据 就用新的data里的数据
+ invisibleListLocalData = item;
+ } else {
+ // 没有就直接存本地
+ locals.invisibleList.push(item);
+ }
+ });
+ data.visibleList.forEach(item => {
+ let localData = locals.visibleList.find(local => item.id === local.id);
+ if (localData) {
+ // 有相同数据 就用新的data里的数据
+ localData = item;
+ } else {
+ // 没有就直接存本地
+ locals.visibleList.push(item);
+ }
+ });
+ }
+ uni.$t.storage.setStorage(`roles_${projectId}`, locals);
+ } catch (error) {
+ console.error('error: ', error);
+ uni.$t.storage.setStorage(`roles_${projectId}`, []);
+ }
+ },
+
+ /**
+ * 定期任务 获取
+ * @param {number} startTime
+ * @param {number} endTime
+ * @returns
+ */
+ async getStorageRegularTask(params) {
+ try {
+ const data = await uni.$t.storage.getStorage(`plan_task_${params.projectId}_${params.roleId}`);
+ return filter.planTask(JSON.parse(data), params.timeNode, params.queryNum, params.timeUnit, params.queryType);
+ } catch (error) {
+ return [];
+ }
+ },
+
+ /**
+ * 定期任务 存
+ * @param {array} data
+ */
+ putStorageRegularTask(params, data) {
+ try {
+ if (!data || !data.length) return; // 服务端没数据不做操作
+ let value = uni.$t.storage.getStorageSync(`plan_task_${params.projectId}_${params.roleId}`);
+ let locals = value ? JSON.parse(value) : [];
+ if (!locals || !locals.length) {
+ // 本地没数据
+ locals = data || [];
+ } else {
+ // 本地有数据
+ data.forEach(item => {
+ let localData = locals.find(local => item.id === local.id);
+ if (localData) {
+ // 有相同数据 就用新的data里的数据
+ localData = item;
+ } else {
+ // 没有就直接存本地
+ locals.push(item);
+ }
+ });
+ }
+ uni.$t.storage.setStorage(`plan_task_${params.projectId}_${params.roleId}`, locals);
+ } catch (error) {
+ console.error('error: ', error);
+ uni.$t.storage.setStorage(`plan_task_${params.projectId}_${params.roleId}`, []);
+ }
+ },
+
+ /**
+ * 永久的日常任务 获取
+ * @param {number} startTime
+ * @param {number} endTime
+ * @returns
+ */
+ async getStoragePermanent(params) {
+ try {
+ const data = await uni.$t.storage.getStorage(`fixed_tasks_${params.projectId}_${params.roleId}`);
+ return filter.fixedTasks(JSON.parse(data));
+ } catch (error) {
+ return [];
+ }
+ },
+
+ /**
+ * 永久的日常任务 存
+ * @param {array} data
+ */
+ putStoragePermanent(params, data) {
+ try {
+ if (!data || !data.length) return; // 服务端没数据不做操作
+ let value = uni.$t.storage.getStorageSync(`fixed_tasks_${params.projectId}_${params.roleId}`);
+ let locals = value ? JSON.parse(value) : [];
+ if (!locals || !locals.length) {
+ // 本地没数据
+ locals = data || [];
+ } else {
+ // 本地有数据
+ data.forEach((item, index) => {
+ let localData = locals.find(local => item.detailId === local.detailId);
+ if (localData) {
+ // 有相同数据 就用新的data里的数据
+ localData = item;
+ } else {
+ locals.splice(index, 1);
+ // 没有就直接存本地
+ locals.push(item);
+ }
+ });
+ }
+ uni.$t.storage.setStorage(`fixed_tasks_${params.projectId}_${params.roleId}`, locals);
+ } catch (error) {
+ console.error('error: ', error);
+ uni.$t.storage.setStorage(`fixed_tasks_${params.projectId}_${params.roleId}`, []);
+ }
+ },
+
+ /**
+ * 日常任务 获取
+ * @param {number} timeNode
+ * @returns
+ */
+ async getDailyTask(params) {
+ try {
+ const data = await uni.$t.storage.getStorage(`variable_tasks_${params.projectId}_${params.roleId}`);
+ return filter.dailyTask(JSON.parse(data), params.timeNode);
+ } catch (error) {
+ return [];
+ }
+ },
+
+ /**
+ * 日常任务 存
+ * @param {array} data
+ */
+ putDailyTask(params, data) {
+ try {
+ if (!data || !data.length) return; // 服务端没数据不做操作
+ let value = uni.$t.storage.getStorageSync(`variable_tasks_${params.projectId}_${params.roleId}`);
+ let locals = value ? JSON.parse(value) : [];
+ if (!locals || !locals.length) {
+ // 本地没数据
+ locals = data || [];
+ } else {
+ // 本地有数据
+ data.forEach(item => {
+ let localData = locals.find(local => item.detailId === local.detailId);
+ if (localData) {
+ // 有相同数据 就用新的data里的数据
+ localData = item;
+ } else {
+ // 没有就直接存本地
+ locals.push(item);
+ }
+ });
+ }
+ uni.$t.storage.setStorage(`variable_tasks_${params.projectId}_${params.roleId}`, locals);
+ } catch (error) {
+ console.error('error: ', error);
+ uni.$t.storage.setStorage(`variable_tasks_${params.projectId}_${params.roleId}`, []);
+ }
+ },
+
+ /**
+ * 插件信息 获取
+ * @param {string} pluginId
+ * @returns
+ */
+ async getPlugin(pluginId) {
+ try {
+ const data = await uni.$t.storage.getStorage(`plugin_${pluginId}`);
+ return filter.plugin(JSON.parse(data));
+ } catch (error) {
+ return null;
+ }
+ },
+
+ /**
+ * 插件信息 存
+ * @param {string} pluginId
+ * @param {object} data
+ */
+ putPlugin(pluginId, data) {
+ try {
+ if (!data || !data.id) return; // 服务端没数据不做操作
+ let value = uni.$t.storage.getStorageSync(`plugin_${pluginId}`);
+ let locals = value ? JSON.parse(value) : null;
+ if (!locals || !locals.length) {
+ // 本地没数据
+ locals = data || null;
+ } else {
+ // 本地有数据
+ locals = data;
+ }
+ uni.$t.storage.setStorage(`plugin_${pluginId}`, locals);
+ } catch (error) {
+ console.error('error: ', error);
+ uni.$t.storage.setStorage(`plugin_${pluginId}`, null);
+ }
+ },
+};
diff --git a/src/utils/cacheAndRequest.js b/src/utils/cacheAndRequest.js
new file mode 100644
index 0000000..2567955
--- /dev/null
+++ b/src/utils/cacheAndRequest.js
@@ -0,0 +1,165 @@
+import store from '@/store/index';
+
+/**
+ * 等待token执行api
+ * 没有token 就延时执行自己 直到有了token在请求
+ * @param {function} requestFn 执行请求的函数
+ */
+export const waitTokenRequest = requestFn => {
+ if (!requestFn || typeof requestFn !== 'function') throw new Error(`requestFn must be a function`);
+ if (uni.$t.storage.getStorageSync(uni.$t.app.tokenKey)) {
+ requestFn();
+ } else {
+ setTimeout(() => waitTokenRequest(requestFn), 10);
+ }
+};
+
+export default {
+ /**
+ * 通过项目id获取角色信息
+ * @param {object} params 提交的参数
+ */
+ findShowRole(params, fn) {
+ let remote = false;
+ if (store.getters.useStorage) {
+ // 有缓存 且 服务端数据未返回 就先返回缓存
+ uni.$t.cache
+ .getShowRole(params.projectId)
+ .then(data => {
+ !remote && fn(null, data);
+ })
+ .catch(err => !remote && fn(err));
+ }
+ waitTokenRequest(() => {
+ // 拿到api数据后 再用api的数据
+ uni.$u.api
+ .findShowRole(params)
+ .then(data => {
+ remote = true;
+ fn(null, data);
+ // 存api到cache里
+ uni.$t.cache.putShowRole(params.projectId, data);
+ })
+ .catch(err => fn(err));
+ });
+ },
+
+ /**
+ * 根据时间基准点和角色查找定期任务
+ * @param {object} params 提交的参数
+ */
+ getRegularTask(params, fn) {
+ let remote = false;
+ if (store.getters.useStorage) {
+ // 有缓存 且 服务端数据未返回 就先返回缓存
+ uni.$t.cache
+ .getStorageRegularTask(params)
+ .then(data => {
+ console.log('cache data: ', data);
+ !remote && fn(null, data);
+ })
+ .catch(err => !remote && fn(err));
+ }
+ waitTokenRequest(() => {
+ // 拿到api数据后 再用api的数据
+ uni.$u.api
+ .getRegularTask(params)
+ .then(data => {
+ console.log('api data: ', uni.$u.deepClone(data));
+ remote = true;
+
+ fn(null, uni.$u.deepClone(data));
+ // 存api到cache里
+ uni.$t.cache.putStorageRegularTask(params, data);
+ })
+ .catch(err => fn(err));
+ });
+ },
+
+ /**
+ * 根据角色查找永久的日常任务
+ * @param {object} params 提交的参数
+ */
+ getPermanent(params, fn) {
+ let remote = false;
+ if (store.getters.useStorage) {
+ // 有缓存 且 服务端数据未返回 就先返回缓存
+ uni.$t.cache
+ .getStoragePermanent(params)
+ .then(data => {
+ !remote && fn(null, data);
+ })
+ .catch(err => !remote && fn(err));
+ }
+ waitTokenRequest(() => {
+ // 拿到api数据后 再用api的数据
+ uni.$u.api
+ .getPermanent(params)
+ .then(data => {
+ remote = true;
+ fn(null, data);
+ // 存api到cache里
+ uni.$t.cache.putStoragePermanent(params, data);
+ })
+ .catch(err => fn(err));
+ });
+ },
+
+ /**
+ * 根据时间和角色查找日常任务
+ * @param {object} params 提交的参数
+ */
+ getGlobal(params, fn) {
+ let remote = false;
+ if (store.getters.useStorage) {
+ // 有缓存 且 服务端数据未返回 就先返回缓存
+ uni.$t.cache
+ .getDailyTask(params)
+ .then(data => {
+ !remote && fn(null, data);
+ })
+ .catch(err => !remote && fn(err));
+ }
+ waitTokenRequest(() => {
+ // 拿到api数据后 再用api的数据
+ uni.$u.api
+ .getGlobal(params)
+ .then(data => {
+ remote = true;
+ fn(null, data);
+ // 存api到cache里
+ uni.$t.cache.putDailyTask(params, data);
+ })
+ .catch(err => fn(err));
+ });
+ },
+
+ /**
+ * 获取插件信息
+ * @param {object} params 提交的参数
+ */
+ getOtherPlugin(params, fn) {
+ let remote = false;
+ if (store.getters.useStorage) {
+ // 有缓存 且 服务端数据未返回 就先返回缓存
+ uni.$t.cache
+ .getPlugin(params.pluginId)
+ .then(data => {
+ !remote && fn(null, data);
+ })
+ .catch(err => !remote && fn(err));
+ }
+ waitTokenRequest(() => {
+ // 拿到api数据后 再用api的数据
+ uni.$u.api
+ .getOtherPlugin(params)
+ .then(data => {
+ remote = true;
+ fn(null, data);
+ // 存api到cache里
+ uni.$t.cache.putPlugin(params.pluginId, data);
+ })
+ .catch(err => fn(err));
+ });
+ },
+};
diff --git a/src/utils/indexedDB.js b/src/utils/indexedDB.js
index 58329ed..30a0e90 100644
--- a/src/utils/indexedDB.js
+++ b/src/utils/indexedDB.js
@@ -28,17 +28,15 @@ const createCollection = (Vue, db) => {
const create = (db, collection, data) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection], 'readwrite').objectStore(collection).add(data);
-
- request.onsuccess = event => {
- console.log(event);
- // FIXME:
- resolve(event);
- };
+ request.onsuccess = () => resolve();
request.onerror = event => {
- console.log(event);
- // FIXME:
- reject(event);
+ const { name, message } = event.target.error;
+ if (name === 'ConstraintError') {
+ reject('数据已存在');
+ } else {
+ reject(message);
+ }
};
});
};
@@ -53,16 +51,8 @@ const create = (db, collection, data) => {
const findOne = (db, collection, key) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection]).objectStore(collection).get(key);
- request.onerror = event => {
- console.log('indexedDB findOne error:', event);
- // FIXME:
- reject(event);
- };
- request.onsuccess = event => {
- console.log('indexedDB findOne success:', event);
- // FIXME:
- resolve(event);
- };
+ request.onerror = event => reject(event.target.error.message);
+ request.onsuccess = event => resolve(event.target.result);
});
};
@@ -75,19 +65,16 @@ const findOne = (db, collection, key) => {
const find = (db, collection) => {
return new Promise((resolve, reject) => {
const request = db.transaction(collection).objectStore(collection).openCursor();
- request.onerror = event => {
- console.log('indexedDB find error:', event);
- reject(event);
- };
+ let result = [];
+
+ request.onerror = event => reject(event.target.error.message);
request.onsuccess = event => {
const cursor = event.target.result;
if (cursor) {
- console.log('indexedDB find success:', cursor);
+ result.push(cursor.value);
cursor.continue();
- // FIXME:
- resolve(event.target.result);
} else {
- console.log('没有更多数据了');
+ resolve(result);
}
};
});
@@ -103,15 +90,8 @@ const find = (db, collection) => {
const update = (db, collection, newData) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection], 'readwrite').objectStore(collection).put(newData);
- request.onerror = event => {
- console.log('indexedDB UPDATE error:', event);
- reject(event);
- };
- request.onsuccess = event => {
- console.log('indexedDB UPDATE success:', event);
- // FIXME:
- resolve(event);
- };
+ request.onerror = event => reject(event.target.error.message);
+ request.onsuccess = () => resolve(newData);
});
};
@@ -125,14 +105,8 @@ const update = (db, collection, newData) => {
const remove = (db, collection, key) => {
return new Promise((resolve, reject) => {
const request = db.transaction([collection], 'readwrite').objectStore(collection).delete(key);
- request.onerror = event => {
- console.log('indexedDB REMOVE error:', event);
- reject(event);
- };
- request.onsuccess = event => {
- console.log('indexedDB REMOVE success:', event);
- resolve(event);
- };
+ request.onerror = event => reject(event.target.error.message);
+ request.onsuccess = () => resolve();
});
};
@@ -146,11 +120,12 @@ const remove = (db, collection, key) => {
*/
const createIndexAndFind = (db, collection, field, key) => {
return new Promise((resolve, reject) => {
- const index = db.transaction([collection], 'readonly').objectStore(collection).index(field);
+ const store = db.transaction([collection], 'readonly').objectStore(collection);
+ store.createIndex(field, field);
+ const index = store.index(field);
const request = index.get(key);
- // FIXME:
- request.onerror = event => reject(event);
- request.onsuccess = event => resolve(event);
+ request.onerror = event => reject(event.target.error.message);
+ request.onsuccess = event => resolve(event.target.result);
});
};
@@ -162,7 +137,7 @@ export const curriedUpdate = curry(update);
export const curriedIndex = curry(createIndexAndFind);
const install = Vue => {
- Vue.prototype.$db = {};
+ uni.$db = Vue.prototype.$db = {};
Vue.prototype.$db.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
const request = Vue.prototype.$db.indexedDB.open(name, Date.now()); // IDBRequest 对象
request.onerror = error => console.error('打开数据库失败', error);
@@ -175,11 +150,14 @@ const install = Vue => {
Vue.prototype.$db.db = event.target.result;
// 创建表
createCollection(Vue, Vue.prototype.$db.db);
- };
- // create
- // console.log(curriedCreate(Vue.prototype.$db.db));
- Vue.prototype.$db.create = curriedCreate(Vue.prototype.$db.db);
+ Vue.prototype.$db.create = curriedCreate(Vue.prototype.$db.db); // create 新增数据,颗粒化以后就不用再传db数据了
+ Vue.prototype.$db.findOne = curriedFindOne(Vue.prototype.$db.db); // 查一条
+ Vue.prototype.$db.find = curriedFind(Vue.prototype.$db.db); // 查集合里的所有数据
+ Vue.prototype.$db.update = curriedUpdate(Vue.prototype.$db.db); // 更新某条数据
+ Vue.prototype.$db.remove = curriedRemove(Vue.prototype.$db.db); // 删除某条数据
+ // Vue.prototype.$db.createIndex = curriedIndex(Vue.prototype.$db.db); // 创建索引
+ };
};
export default { install };
diff --git a/src/utils/request.js b/src/utils/request.js
index a20b670..2cf5374 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -11,8 +11,9 @@ const install = (Vue, vm) => {
// 请求拦截部分,如配置,每次请求前都会执行
Vue.prototype.$u.http.interceptor.request = config => {
- if (vm.$store.state.user.token) {
- config.header.Authorization = `Bearer ${vm.$store.state.user.token}`;
+ const token = vm.$store.state.user.token || uni.$t.storage.getStorageSync(uni.$t.app.tokenKey);
+ if (token) {
+ config.header.Authorization = `Bearer ${token}`;
}
return config;
diff --git a/src/utils/storage.js b/src/utils/storage.js
index 01d115c..ea672d6 100644
--- a/src/utils/storage.js
+++ b/src/utils/storage.js
@@ -39,6 +39,7 @@ export default {
* @param {*} data
*/
setStorage(key, data) {
+ uni.$t.storage.checkCapacity();
return new Promise((resolve, reject) => {
const value = typeof data === 'string' ? data : JSON.stringify(data);
uni.setStorage({
@@ -67,7 +68,7 @@ export default {
resolve(res.data);
},
fail(error) {
- reject(`数据${key}获取失败, error: ${error}`);
+ reject(`数据${key}获取失败, error: ${error.errMsg}`);
},
});
});
@@ -97,4 +98,15 @@ export default {
clearStorage() {
uni.clearStorage();
},
+
+ // 检测local Storage容量 超出容量清空数据缓存
+ checkCapacity() {
+ /* #ifdef H5 */
+ const capacity = JSON.stringify(localStorage).length;
+ let max = 1024 * 1024 * 4;
+ if (capacity >= max) {
+ uni.$t.storage.clearStorage();
+ }
+ /* #endif */
+ },
};
diff --git a/src/utils/tall.js b/src/utils/tall.js
index 8594b15..19c5b17 100644
--- a/src/utils/tall.js
+++ b/src/utils/tall.js
@@ -1,11 +1,15 @@
import app from '@/config/app.js';
-import timeConfig from '@/config/time';
-import zIndex from '@/config/zIndex.js';
+import cache from '@/utils/cache.js';
+import cacheAndRequest from '@/utils/cacheAndRequest.js';
import plugin from '@/config/plugin.js';
import storage from '@/utils/storage.js';
import time from '@/utils/time.js';
+import timeConfig from '@/config/time';
import ui from '@/utils/ui.js';
import upload from '@/utils/upload.js';
+import user from '@/config/user.js';
+import zIndex from '@/config/zIndex.js';
+import task from '@/config/task.js';
const gateway = process.env.VUE_APP_API_URL;
@@ -19,6 +23,10 @@ const $t = {
ui, // ui界面提示相关
chooseAndUpload: upload.chooseAndUpload, // 选择并上传单个文件相关的封装
domain: `${gateway}/defaultwbs`,
+ cache, // 本地存储相关
+ $q: cacheAndRequest,
+ user, // 用户相关配置
+ task, // 任务相关配置
};
uni.$t = $t;
diff --git a/src/utils/task.js b/src/utils/task.js
new file mode 100644
index 0000000..17dd2f8
--- /dev/null
+++ b/src/utils/task.js
@@ -0,0 +1,53 @@
+import dayjs from 'dayjs';
+
+/**
+ * 设置时间轴空数据
+ * @param {number} startTime
+ * @param {boolean} isUp true 向上加载,false 向下加载
+ * @param {string} timeGranularity 颗粒度
+ * @param {number} pageCount 加载的颗粒度数量 默认值是10
+ */
+export const setPlaceholderTasks = (startTime, isUp, timeGranularity, pageCount) => {
+ let result = [];
+ pageCount = pageCount || uni.$t.task.pageCount;
+ for (let i = 0; i < pageCount; i++) {
+ const delta = isUp ? `-${i + 1}` - 0 : i + 1;
+ let item = {
+ id: uni.$u.guid(20, false, 10),
+ panel: {},
+ plugins: [],
+ process: 4,
+ planStart: uni.$moment(startTime).add(delta, timeGranularity).valueOf(),
+ };
+ // console.log('isup: ', isUp, 'result:', new Date(item.planStart).toLocaleDateString());
+
+ isUp ? result.unshift(item) : result.push(item);
+ }
+ return result;
+};
+
+/**
+ * 超出旧数据上、下限 补齐时间刻度到新数据的起始时间颗粒度
+ * @param {object} option
+ * @param {array} option.tasks 旧的已有的任务书籍
+ * @param {array} option.data 新拿到的任务数据 空值已经过滤过了
+ * @param {string} option.timeGranularity 颗粒度
+ */
+export const computeFillPlaceholderTaskCount = ({ tasks, data, timeGranularity }) => {
+ const result = { prev: 0, next: 0 };
+ // 新数据的开始时间 < 旧数据的开始时间
+ // 超出了上限 补上限的时间刻度
+ // 补上 新数据开始时间 到 旧数据开始时间 的刻度
+ if (+data[0].planStart < +tasks[0].planStart) {
+ // 找出来需要补几组颗粒度
+ result.prev = dayjs(+tasks[0].planStart).diff(+data[0].planStart, timeGranularity) + 1;
+ }
+
+ // 新数据的结束时间 > 旧数据的结束时间
+ // 超出了下线 补下限的时间刻度
+ // 补上 旧数据截止时间 到 新数据截止时间 的刻度
+ if (+data[data.length - 1].planStart > +tasks[tasks.length - 1].planStart) {
+ result.next = dayjs(+data[data.length - 1].planStart).diff(+tasks[tasks.length - 1].planStart, timeGranularity) + 1;
+ }
+ return result;
+};
diff --git a/src/utils/time.js b/src/utils/time.js
index 6f1fae2..5c7fa22 100644
--- a/src/utils/time.js
+++ b/src/utils/time.js
@@ -82,7 +82,7 @@ const setTimestampToStr = timestamp => {
const day = formatNumber(timeObj.getDate());
const hour = formatNumber(timeObj.getHours());
const minute = formatNumber(timeObj.getMinutes());
- const date = `${year}/${month}/${day}`;
+ const date = `${year}-${month}-${day}`;
const time = `${hour}:${minute}`;
return {
date,
@@ -104,12 +104,9 @@ const validateTimeIsToday = time => {
* 检测两个日期是否相同
* @param {number | date} time
* @param {number | date} value
- * @param {string} cycle 传入 day 将会比较 day、 month和 year
+ * @param {string} cycle 传入 day 将会比较 day、 month和 year “一般是时间颗粒度”
*/
-const isSame = (time, value, cycle) => {
- const str = dayjs(time).isSame(value, cycle);
- return str;
-};
+const isSame = (time, value, cycle) => dayjs(time).isSame(value, cycle);
/**
* 格式化开始时间
diff --git a/tailwind.config.js b/tailwind.config.js
deleted file mode 100644
index 4ab9476..0000000
--- a/tailwind.config.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const colors = require('tailwindcss/colors');
-
-module.exports = {
- // purge: ['./public/index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
- darkMode: false, // or 'media' or 'class'
- theme: {
- extend: {},
- colors: {
- blue: colors.sky,
- gray: colors.blueGray,
- red: colors.red,
- orange: colors.orange,
- yellow: colors.yellow,
- green: colors.green,
- pink: colors.rose,
- white: colors.white,
- black: '#333',
- transparent: 'transparent',
- },
- },
- variants: { extend: {} },
- plugins: [],
- corePlugins: {
- space: false,
- divideWidth: false,
- divideColor: false,
- divideStyle: false,
- divideOpacity: false,
- },
-};
diff --git a/vue.config.js b/vue.config.js
index 5a63af9..9506e1a 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -10,6 +10,7 @@ module.exports = {
devServer: {
// open: true,
// host: '127.0.0.1',
+ port: 9000,
overlay: { warnings: false, errors: true },
// proxy: {}
},
@@ -29,9 +30,8 @@ module.exports = {
},
pluginOptions: {
// mock: { entry: './src/mock/mock.js', debug: true, disable: true },
- eruda: {},
- webpackBundleAnalyzer: {
- openAnalyzer: isPro,
- },
+ // webpackBundleAnalyzer: {
+ // openAnalyzer: isPro,
+ // },
},
};