您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
2023/11/28 16:37:43
当前为
// ==UserScript== // @name 易用云 // @namespace 让易搭云更易用!好用到爆炸!(云生集团-研发专用版) // @version 0.1.15 // @match https://web.yidayun.com/* // @icon https://www.yidayun.com/images/favicon.png // @grant none // @author Jack.Chan ([email protected]) // @namespace http://fulicat.com // @url https://gf.qytechs.cn/zh-CN/scripts/480426 // @license MIT // @description 2023/11/28 16:37:43 // ==/UserScript== (function() { // 忽略注入类型 if (document.contentType !== 'text/html' || (/\w+\.{1,1}\w+/.test(location.pathname) && !/\w+\.{1,1}html/.test(location.pathname) ) || /\w+\.{2,}\w+/.test(location.pathname) || /^\/preview\//.test(location.pathname)) { console.warn(`不支持在此类型文档中注入,`, document.contentType); return false; } // html类型 + 非iframe嵌套时 清空 body if (/\w+\.{1,1}html/.test(location.pathname) && window.top === window) { document.body.innerHTML = ''; } // 图标 const ICONS = { close: ` <svg width="16px" height="16px" viewBox="0 0 10 10" version="1.1"> <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <path d="M8.95969723,0.897476866 C9.21843425,1.15582278 9.24028631,1.56159861 9.02504921,1.84484482 L8.96046978,1.91885304 L5.91916574,4.96548241 C5.92235682,5.00422322 5.92243302,5.04317194 5.91939467,5.08192184 L8.95969664,8.1196985 C9.21843396,8.37804412 9.24028649,8.78381992 9.02504971,9.06706638 L8.96047037,9.14107467 C8.70212475,9.399812 8.29634895,9.42166452 8.01310249,9.20642774 L7.9390942,9.1418484 L5.01806209,6.22532901 L2.09858553,9.1418484 L2.02457724,9.20642774 C1.74133078,9.42166452 1.33555498,9.399812 1.07720936,9.14107467 L1.07720936,9.14107467 L1.01263002,9.06706638 C0.797393239,8.78381992 0.819245764,8.37804412 1.07798309,8.1196985 L1.07798309,8.1196985 L4.11828506,5.08192184 C4.1152467,5.04317194 4.11532291,5.00422322 4.11851399,4.96548241 L1.07720994,1.91885304 L1.01263052,1.84484482 C0.797393414,1.56159861 0.819245474,1.15582278 1.0779825,0.897476866 C1.36024108,0.615644961 1.81752677,0.615990848 2.09935867,0.898249425 L2.09935867,0.898249425 L5.01906209,3.82132901 L7.93832106,0.898249425 C8.22015296,0.615990848 8.67743865,0.615644961 8.95969723,0.897476866 Z" fill="currentColor" fill-rule="nonzero"></path> </g> </svg> `.trim(), star: ` <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" class="svg-icon svg-icon-star"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> `.trim(), starred: ` <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" class="svg-icon svg-icon-star-fill svg-icon-starred"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"></path> </svg> `.trim(), pin: ` <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" class="svg-icon svg-icon-pin"> <path d="m11.294.984 3.722 3.722a1.75 1.75 0 0 1-.504 2.826l-1.327.613a3.089 3.089 0 0 0-1.707 2.084l-.584 2.454c-.317 1.332-1.972 1.8-2.94.832L5.75 11.311 1.78 15.28a.749.749 0 1 1-1.06-1.06l3.969-3.97-2.204-2.204c-.968-.968-.5-2.623.832-2.94l2.454-.584a3.08 3.08 0 0 0 2.084-1.707l.613-1.327a1.75 1.75 0 0 1 2.826-.504ZM6.283 9.723l2.732 2.731a.25.25 0 0 0 .42-.119l.584-2.454a4.586 4.586 0 0 1 2.537-3.098l1.328-.613a.25.25 0 0 0 .072-.404l-3.722-3.722a.25.25 0 0 0-.404.072l-.613 1.328a4.584 4.584 0 0 1-3.098 2.537l-2.454.584a.25.25 0 0 0-.119.42l2.731 2.732Z"></path> </svg> `.trim(), copy: ` <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" class="svg-icon svg-icon-copy"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> `.trim(), check: ` <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" class="svg-icon svg-icon-check"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> `.trim(), }; String.prototype.trimHTML = function() { var html = this.trim(); html = html.replace(/<!--[\s\S]*?-->/g, ''); // html = html.replace(/>\s+</g, '><'); html = html.replace(/>\s</g, '><'); html = html.replace(/>\t</g, '><'); html = html.replace(/>\n</g, '><'); html = html.replace(/>\n\t+</g, '><'); return html; } const formatDate = (timestamp) => { if (timestamp) { return new Date(timestamp).toLocaleString(); } return ''; } const copyElementContents = (el) => { return new Promise((resolve, reject) => { if (!el) { return reject(new Error('el not found')); } if (this.timer_copy) { clearTimeout(this.timer_copy); this.timer_copy = null; } var body = document.body, range, sel; if (document.createRange && window.getSelection) { range = document.createRange(); sel = window.getSelection(); sel.removeAllRanges(); try { range.selectNodeContents(el); sel.addRange(range); } catch (e) { range.selectNode(el); sel.addRange(range); } } else if (body.createTextRange) { range = body.createTextRange(); range.moveToElementText(el); range.select(); } document.execCommand('Copy'); this.timer_copy = setTimeout(() => { window.getSelection().empty(); resolve(); }, 250); }); } const renderLinkHref = (data) => { const view = { type: 'windowAction', target: 'tab', object: data.object, name: (data.title || (data.project + data.name)).substr(0, 50), resId: data.resId, viewNumber: data.viewNumber, // context: { flowFlag: true } }; if (data.context) { view.context = data.context; } return `https://web.yidayun.com/home?view=${ encodeURIComponent(JSON.stringify(view)) }`; }; const renderPlayers = (players) => { if (!players) { return ''; } try { players = JSON.parse(players); players = Array.isArray(players) ? players.join('、') : JSON.stringify(players); } catch (ex) { // console.warn(ex); } return players; }; const renderField = (value) => { // console.log('v:', value); if (value === undefined || value === null) { value = ''; } if (typeof value === 'string') { value = value.trim(); } return value; } const trimObject = (object) => { if (object === undefined || object === null) { return ''; } if (typeof object === 'string') { return object.trim(); } if (typeof object === 'object') { if (Array.isArray(object)) { return object.map((item) => { return trimObject(item); }); } for (var key in object) { if (object[key] === undefined || object[key] === null) { object[key] = ''; } else if (typeof object[key] === 'string') { object[key] = trimObject(object[key]); } } return object; } return object; } const doCopy = (text) => { return new Promise((resolve, reject) => { if (typeof text !== 'string') { return resolve(''); } text = text.trim(); var $text = document.createElement('textarea'); $text.setAttribute('readonly', 'readonly'); $text.style.cssText = 'width: 10px;height: 10px;position: fixed;top:-999px;left:-999px;'; $text.value = text; document.body.appendChild($text); $text.select(); if (this.timer_copy) { clearTimeout(this.timer_copy); this.timer_copy = null; } this.timer_copy = setTimeout(() => { if (document.execCommand('copy')) { resolve(text); } else { reject(text); } this.timer_copy = setTimeout(() => { this.timer_copy = null; document.body.removeChild($text); }, 100); }, 250); }); } // @ request const $fetch = (url, data, options) => { options = { method: 'POST', mode: 'cors', timeout: 30000, credentials: 'omit', ...options }; options.headers = { 'content-type': 'application/json', ...options.headers }; options.headers['Accept'] = 'application/json, text/plain, */*'; options.headers['X-Session'] = document.cookie; if (data) { if (options.method.toUpperCase() === 'GET' || options.method.toUpperCase() === 'HEAD') { url+= (url.indexOf('?') > -1 ? '&' : '?') + (new URLSearchParams(data)).toString(); } else { options.body = typeof data === 'object' ? JSON.stringify(data) : data; } } return new Promise((resolve, reject) => { fetch(url, options, options.timeout).then((res) => res.json()).then((res) => { if (res.errorCode === 0 && res.success) { resolve(res); } else { console.error('[ERR]', url, options, res); reject(res); } }).catch((err) => { reject(err); }); }); } // 用户信息 var USER_INFO = { data: {}, set(data) { this.data = data; }, get(key) { if(key) { return this.data[key]; } return this.data; } } class BTN_SHARE { get name() { return '分享按钮'; } #root = null; #btnClassName = 'y-app-link-btn-share'; // #btnSelector = '.y-app-link-btn-share'; #btnSelector = '.'+ this.#btnClassName; constructor() { console.log(`[OK] 初始化 ${ this.name } ...`); this.init(); } getShareLink(params) { if (typeof params !== 'object' || !params.objectNumber || !params.dataId) { console.warn(`[WARN] 参数错误`, params); return Promise.reject('params error'); } return $fetch('https://api.yidayun.com/share/getShareLink', { context: {}, params: { objectNumber: params.objectNumber, dataId: params.dataId } }).then((res) => { console.log('getShareLink:', res.data); if (typeof res.data === 'object') { params.url = res.data.privateLink || res.data.publicLink || JSON.stringify(res.data); } else { params.url = res.data; } return { ...params, ...res.data }; }).catch((err) => { console.warn('[WARN]', err); return err; }); } inject($el) { // $el is current tab if (!$el) { return; } if ($el.querySelector(this.#btnSelector)) { return console.warn(`[WARN] 已注入 ${ this.name }`); } $el.$btnShare = this.createBtn($el); $el.$btngroup.insertBefore($el.$btnShare, $el.$btngroup.childNodes[0]); $el.dataset.injected = true; } // 查找目标元素 findTarget(next) { if (!this.$root) { return; } // var $el = this.$root.querySelector('.ant-tabs-tabpane.ant-tabs-tabpane-active.eb-home-tabs-tab.eb-home-tabs-tab-viewForm .eb-view-toolbar-form-head>.ant-space.ant-formily-button-group'); var $el = this.$root.querySelector('.ant-tabs-tabpane.ant-tabs-tabpane-active.eb-home-tabs-tab.eb-home-tabs-tab-viewForm'); $el = $el || this.$root.querySelector('.eb-share-form-view'); if (!$el) { if (typeof next === 'function') { next($el); } return false; } $el.$btngroup = $el.querySelector('.eb-view-toolbar-form-head>.ant-space.ant-formily-button-group'); if (!$el.$btngroup) { if (typeof next === 'function') { next($el); } return false; } if ($el.querySelector(this.#btnSelector)) { console.warn(`[WARN] 已注入 ${ this.name }`); return false; } this.inject($el); return $el; } // 获取当前 tab 信息 getTabInfo(tabId) { if (!tabId) { return console.error('[ERR]', `tabId is ${ tabId }`); } var info = null; var tabs = window.sessionStorage.getItem(USER_INFO.get('keyTabs')); try { tabs = JSON.parse(tabs); if (tabs && tabs.length) { tabs = tabs.filter((item) => item.id === tabId); if (tabs.length) { info = tabs[0]; } } } catch (ex) { console.error(ex); } return info; } // 获取详情页字段信息 getDetailfields($el) { var fields = {}; // $el is current tab if (!$el) { return fields; } var $gridItems = $el.querySelectorAll('.ant-formily-grid-layout>.ant-formily-item'); $gridItems.forEach((item) => { var text = item.innerText.replace(/\n/g, ''); if (text.startsWith('标题:') || text.startsWith('需求标题:')) { fields.title = text.split(':').pop(); } if (text.startsWith('所属项目:')) { fields.project = text.split(':').pop(); } }); return fields; } createBtn($el) { // $el is current tab if (!$el) { return; } var $btnCopy = document.createElement('div'); $btnCopy.className = 'ant-space-item'; $btnCopy.innerHTML = `<a class="${ this.#btnClassName }" target="_blank" rel="opener" href="javascript:void(0)" title="复制分享链接">分享</a>`; $btnCopy.$link = $btnCopy.querySelector(this.#btnSelector); $btnCopy.$link.addEventListener('click', this.onBtnClick($el)); return $btnCopy; } doCopy(event, data) { doCopy(`${ (data.project ? `【${ data.project }】 ` : '') }${ data.title } \n${ data.url }`).then(() => { event.target.innerText = '复制成功'; }).finally(() => { setTimeout(() => { event.target.innerText = '分享'; }, 3000); }); } onBtnClick($el) { let data = null; let loading = false; let canShare = true; return (event) => { event.stopPropagation(); if (!event.ctrlKey || event.target.getAttribute('href').includes('javascript:void(0)') || data) { event.preventDefault(); if (data && data.url) { return this.doCopy(event, data); } // 分享详情页 if ($el.classList.contains('eb-share-form-view')) { data = this.getDetailfields($el); /*if (data.title && window.parent.$Y && window.parent.$Y.$app && window.parent.$Y.$app.$search) { window.parent.$Y.$app.$search.$keyword.value = data.title; } */ if (window.location.hash.startsWith('#/share/form?number=')) { data.url = location.hash.substr(1); } if ((window.location.pathname + window.location.search).startsWith('/share/form?number=')) { data.url = window.location.pathname + window.location.search; } if (data.url) { data.url = data.url.split('&callback')[0]; } if (data.url) { data.url = `https://web.yidayun.com${ data.url }`; event.target.setAttribute('href', data.url); // console.log('share.data:', data); this.doCopy(event, data); return false; } // console.log('share.data:', data); canShare = false; event.target.innerText = '无法分享'; event.target.title = '解析异常了'; return false; } // 详情页 if (!canShare || loading) { return false; } var tabId = $el.id.split('-panel-').pop(); if (!tabId) { return console.warn(`找不到 对应的 tabId`, tabId); } var tabInfo = this.getTabInfo(tabId); if (!tabInfo) { return console.warn(`找不到 对应的 tab`, tabId, tabInfo); } data = this.getDetailfields($el); // 请求数据 event.target.innerText = '获取中...'; this.getShareLink({objectNumber: tabInfo.object, dataId: tabInfo.resId}).then((res) => { data = { ...data, ...res }; // console.log('data:', data); if (data.url) { event.target.setAttribute('href', data.url); this.doCopy(event, data); } else { canShare = false; event.target.innerText = '无法分享'; event.target.title = '易搭云不支持'; } }).finally(() => { loading = false; }); return false; } } } watchEvents() { const findEl = () => { if (this.timer_finder) { clearTimeout(this.timer_finder); this.timer_finder = null; } this.timer_finder = setTimeout(() => { this.findTarget(($el) => { this.timer_finder = null; if ($el && $el.dataset.injected !== 'true') { this.timer_finder = setTimeout(() => { this.timer_finder = null; this.findTarget(); }, 600); } }); }, 600); } // 监听 查找 可以分享的页面 this.$root.addEventListener('click', (event) => { if (!event.clientX && !event.clientY) { return false; } findEl(); // console.log('body.clicked', event); }); setTimeout(() => { findEl(); }, 1200); console.log(`[OK] 初始化 ${ this.name } 监听事件`); } init() { if (this.inited) { return console.warn(`[WARN] 已经初始化过了`); } this.$root = document.querySelector('#root'); // this.$root = document.body; if (!this.$root) { return console.error(`[ERROR] 监控父元素未找到`); } this.watchEvents(); this.inited = true; } } class PLAYERS { name = '参与人选择器'; #key = 'y-app-players'; #separator = ','; $root = null; constructor() { console.log(`[OK] 初始化 参与人选择器 ...`); this.init(); } parserArray(str) { str = (str || '').toString().trim(); str = str.replace(/(,|,|;|\s)+/ig, this.#separator); str = str.split(this.#separator); str = str.filter((item, index, array) => { return item.trim().length && array.indexOf(item) === index; }); return str; } get() { let data = window.localStorage.getItem(this.#key); return this.parserArray(data); } set(data) { if (typeof data === 'object') { data = data.join(this.#separator); } if (typeof data === 'string') { data = data.trim(); window.localStorage.setItem(this.#key, data); } } clear() { window.localStorage.removeItem(this.#key); } // 注入样式 injectStyle() { const cssRules = () => { return ` .y-app-players{ &>.ant-space{ width: 100%; } .y-app-players__editor{ display: none; } .y-app-players__selector{ } &.y-app-players__editing{ .y-app-players__editor{ display: flex; } .y-app-players__selector{ display: none; } } .y-app-players__list, .y-app-players__actions{ padding-top: 3px; padding-bottom: 3px; } .y-app-players__list{ flex: 1; } .y-app-players__item, .y-app-players__placeholder, .y-app-players__btn{ display: inline-block; } .y-app-players__btn, .y-app-players__item{ min-width: 30px; text-align: center; padding: 2px 6px; border-radius: 3px; &:hover{ background: #f5f5f5; } &:active{ background: #e5e5e5; } } .y-app-players__item{ margin-right: 5px; margin-bottom: 4px; } .y-app-players__item-selected{ color: #fff; background: #247fff; &:hover{ background: #4b96ff; } &:active{ background: #146eed; } } .y-app-players__placeholder{ color: #999; padding: 2px 6px; } .y-app-players__btn-clear{ color: red; } } div.ant-tabs-tabpane-active[id^="rc-tabs"][id$="-panel-person"]{ .eb-index-list-bar, .eb-selector-modal-person-index{ display: none !important; } .eb-index-list-container{ margin-top: -20px !important; } } `.trim(); }; const $style = document.createElement('style'); $style.setAttribute('id', 'y-app-style-players'); $style.setAttribute('type', 'text/css'); $style.innerHTML = cssRules(); document.head.appendChild($style); console.log(`[OK] 初始化 参与人选择器 已注入`); } inject($el) { if (!$el) return false; var render = (data, defaultValue) => { var html = []; var hasSelected = false; var selectedList = $el.getSelectedList(); // console.log(selectedList, data); if (Array.isArray(data) && data.length) { data.forEach((item, index) => { // hasSelected = selectedList.includes(item); hasSelected = selectedList.filter((dd) => dd == item).length; html.push(`<a class="y-app-players__item${ hasSelected ? ' y-app-players__item-selected' : '' }" title="左键单击:选择 右键单击:前移 左键长按:移除" data-index="${ index }">${ item }</a>`); }); } else { defaultValue = defaultValue || `<span class="y-app-players__placeholder">搜索后将添加常联系的,多个用空格隔开</span>`; if (defaultValue) { html.push(defaultValue); } } return html.join(''); } // 获取已选择的 $el.getSelectedList = () => { var ret = $el.$selectedList ? $el.$selectedList.innerText : ''; ret = ret.split('\n'); ret = ret.filter((item) => item.trim()); return ret; } // 自动选择 $el.autoSelect = (next) => { if ($el.timer_search) { clearTimeout($el.timer_search); $el.timer_search = null; } if ($el.timer_search_render) { clearTimeout($el.timer_search_render); $el.timer_search_render = null; } $el.timer_search = setTimeout(() => { $el.$results = $el.$content.querySelectorAll('.eb-selector-modal-person-item'); // 有搜索结果时,保存数据、更新视图 if ($el.$results.length) { // 只有一个结果时自动选中 if ($el.$results.length === 1) { $el.$results[0].click(); } $el.timer_search_render = setTimeout(() => { if (typeof next === 'function') { next($el.$results); } // 保存数据 this.set($el.data); // 更新视图 $el.$players.$list.innerHTML = render($el.data).trimHTML(); }, 200); } }, 500); } // $el.$content = $el.parentNode.parentNode.parentNode.parentNode; // $el.$body = $el.$content.parentNode; $el.$content = $el.querySelector('.ant-modal-content'); $el.$body = $el.$content.querySelector('.ant-modal-body'); // 展开已选择 $el.doExpand = () => { //$el.$btnHasSelected = $el.$content.querySelector('a.ant-typography[direction="ltr"]'); $el.$btnHasSelected = $el.$content.querySelector('.eb-selector-modal-footer .ant-space-item>.ant-typography'); if ($el.$btnHasSelected) { if ($el.classList.contains('eb-selector-modal--open')) { // console.warn('已经展开'); // 已经展开 return false; } else { // 点击展开已选择 $el.$btnHasSelected.click(); } setTimeout(() => { $el.$players.$list.innerHTML = render($el.data).trimHTML(); }, 1200); } } // 自动展开已选择 $el.doExpand(); if ($el.$body) { $el.$body.addEventListener('click', (event) => { // event.stopPropagation(); return false; }); $el.$selectedList = $el.$body.querySelector('.eb-selector-modal-drawer-content>.eb-menu-sm'); $el.$selectedList.addEventListener('click', function() { if ($el.$selectedList.timer_click) { clearTimeout($el.$selectedList.timer_click); $el.$selectedList.timer_click = null; } $el.$selectedList.timer_click = setTimeout(() => { $el.$players.$list.innerHTML = render($el.data).trimHTML(); }, 300); }) } // console.log('b:', $el.$body, $el.$selectedList); $el.$tree = $el.querySelector('.eb-selector-modal-tree'); $el.$input = $el.querySelector('input.ant-input[type="text"]'); // 输入 $el.doInput = (value, next) => { // 赋值给输入框 var lastValue = $el.$input.value; $el.$input.value = value; $el.$input.setAttribute('value', value); var eventInput = new Event('input', { target: $el.$input, bubbles: true }); eventInput.simulated = true; var tracker = $el.$input._valueTracker; if (tracker) { tracker.setValue(lastValue); } $el.$input.dispatchEvent(eventInput); if (typeof next === 'function') { next(); } } // 搜索 $el.doSearch = (next) => { // 执行搜索 var eventEnter = new KeyboardEvent('keydown', { code: 'Enter', key: 'Enter', charCode: 13, keyCode: 13, view: window, bubbles: true }); $el.$input.dispatchEvent(eventEnter); if (typeof next === 'function') { next(); } } // 输入空格组织 垃圾转圈 $el.doInput('___________', () => { $el.doSearch(() => { $el.doInput(''); }); }); $el.data = this.get(); $el.$players = document.createElement('div'); $el.$players.className = 'ant-space-item y-app-players'; var html = ` <div class="ant-space y-app-players__tip"><span class="y-app-players__placeholder">左键单击选择,左键长按2秒删除,右键移至最前</span></div> <div class="ant-space y-app-players__selector"> <div class="ant-space-item y-app-players__list"></div> <div class="ant-space-item y-app-players__actions"> <a class="y-app-players-btn y-app-players__btn-clear" title="三思 !!! 清空保存的历史 左键长按姓名也可删除">清空</a> </div> </div> `.trim(); $el.$players.innerHTML = html.trimHTML(); $el.$players.$list = $el.$players.querySelector('.y-app-players__list'); $el.$players.$list.innerHTML = render($el.data).trimHTML(); // 双击 复制全部常联系的 $el.$players.$list.addEventListener('dblclick', (event) => { event.preventDefault(); event.stopPropagation(); if (event.target.tagName === 'A') { return false; } var value = $el.data.join(' '); doCopy(value).then(() => { console.log(`常联系的 复制成功`); console.log(value); }); }); // 右键 排序 $el.$players.$list.addEventListener('contextmenu', (event) => { event.preventDefault(); event.stopPropagation(); if (event.target.tagName !== 'A' && event.target.dataset.index === undefined) { return false; } var index = Number(event.target.dataset.index); if (isNaN(index)) { // console.warn(`index isNaN`, event.target.dataset.index); return false; } // 移动至第一 var value = $el.data.splice(index, 1); $el.data.unshift(value); this.set($el.data); $el.$players.$list.innerHTML = render($el.data).trimHTML(); }); // 长按2秒 移除 $el.$players.$list.addEventListener('mousedown', (event) => { event.preventDefault(); event.stopPropagation(); if (event.target.tagName !== 'A' && event.target.dataset.index === undefined) { return false; } if (event.button !== 0) { return false; } var index = Number(event.target.dataset.index); if (isNaN(index)) { // console.warn(`index isNaN`, event.target.dataset.index); return false; } var value = $el.data[index]; if (!value) { return false; } if ($el.$players.$list.timer_mousedown) { clearTimeout($el.$players.$list.timer_mousedown); $el.$players.$list.timer_mousedown = null; } $el.$players.$list.dataset.mousedowned = true; $el.$players.$list.timer_mousedown = setTimeout(() => { // 移除 $el.data.splice(index, 1); this.set($el.data); $el.$players.$list.innerHTML = render($el.data).trimHTML(); }, 2000); }); $el.$players.$list.addEventListener('mouseup', (event) => { if ($el.$players.$list.timer_mousedown) { clearTimeout($el.$players.$list.timer_mousedown); $el.$players.$list.timer_mousedown = null; } }); // 左键 选择 $el.$players.$list.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); if (event.target.tagName !== 'A' && event.target.dataset.index === undefined) { return false; } if (event.button !== 0) { return false; } var index = Number(event.target.dataset.index); if (isNaN(index)) { // console.warn(`index isNaN`, event.target.dataset.index); return false; } var value = $el.data[index]; if (!value) { return false; } $el.doInput(value, $el.doSearch); // 自动选择 $el.autoSelect(() => { // 最近点击的插入到最前排 // value = $el.data.splice(index, 1); // $el.data.unshift(value); }); }); // 清空 按钮 $el.$players.$clear = $el.$players.querySelector('.y-app-players__btn-clear'); $el.$players.$clear.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); $el.data = []; // window.localStorage.removeItem('y-app-players'); this.clear(); $el.$players.$list.innerHTML = render($el.data).trimHTML(); }); $el.$tree.insertBefore($el.$players, $el.$tree.childNodes[0]); // 搜索框 事件 $el.$input.addEventListener('keyup', (event) => { if (event.key !== 'Enter') { return false; } var value = $el.$input.value.trim(); if (!value) { return false; } var currentValue = value; value = this.parserArray(value); value = value.concat($el.data); value = this.parserArray(value.join(',')); $el.data = value; $el.$players.$list.innerHTML = render(value).trimHTML(); this.set($el.data); // 自动选择 $el.autoSelect(); }); // 标记元素已经找到 $el.dataset.injected = true; return $el; } findModal(next) { // var $el = document.querySelector('div.ant-tabs-tabpane-active[id^="rc-tabs"][id$="-panel-person"]'); var $el = document.querySelector('.ant-modal-wrap:not([style*="none"])>.ant-modal.eb-selector-modal'); if (!$el) { if (typeof next === 'function') { next($el); } return false; } if ($el.querySelector('.y-app-players')) { console.warn(`[WARN] 已注入 参与人选择器`); if ($el.doExpand) { $el.doExpand(); } return false; } this.inject($el); return $el; } watchEvents() { // 监听 查找 参与人选择 弹窗 this.$root.addEventListener('click', (event) => { if (this.timer_finder) { clearTimeout(this.timer_finder); this.timer_finder = null; } if (!event.clientX && !event.clientY) { return false; } this.timer_finder = setTimeout(() => { this.findModal(($el) => { this.timer_finder = null; if ($el && $el.dataset.injected !== 'true') { this.timer_finder = setTimeout(() => { this.timer_finder = null; this.findModal(); }, 600); } }); }, 600); // console.log('body.clicked', event); }); console.log(`[OK] 初始化 参与人选择器 监听事件`); } init() { if (this.inited) { return console.warn(`[WARN] 参与人选择器 已经初始化过了`); } // this.$root = document.querySelector('#root'); this.$root = document.body; if (!this.$root) { return console.error(`[ERROR] 监控父元素未找到`); } this.watchEvents(); this.injectStyle(); this.inited = true; } } class BOOKMARKS { name = '收藏夹'; #key = 'y-app-bookmarks'; #DB = {}; constructor() { console.log(`[OK] 初始化 收藏夹 ...`); this.#load(); } #check = (data) => { if (!data || typeof data !== 'object') { console.warn(`[WARN] 参数错误, 类型错误, 只接受简单对象`, data) return false; } if (!data.object) { console.warn(`[WARN] 参数错误, 缺少object`, data.object) return false; } if (!data.resId) { console.warn(`[WARN] 参数错误, 缺少resId`, data.resId) return false; } return true; } #load = () => { let DB = window.localStorage.getItem(this.#key); if (!DB) { return; } try { DB = JSON.parse(DB); if (typeof DB === 'object') { for (var object in DB) { if (Array.isArray(DB[object]) && DB[object].length) { DB[object].forEach((item, index) => { ((_item, _index) => { if (_item.resId) { DB[object][_item.resId] = DB[object][_index]; } })(item, index); }); } } this.#DB = DB; } } catch (ex) { console.error(`[ERROR] 加载&解析数据出错`, ex); } } #save = () => { window.localStorage.setItem(this.#key, JSON.stringify(this.#DB)); } get length() { const DB = this.#DB; let count = 0; for (var object in DB) { count = count + parseInt(DB[object].length); } return count; } get get() { return (viewObject, index) => { if (typeof viewObject === 'string' && viewObject) { const viewData = this.#DB[viewObject]; if (viewData && index !== undefined) { return viewData[index]; } return viewData; } return this.#DB; } } get add() { return (data, callback) => { if (!this.#check(data)) { return false; } const DB = this.#DB; if (!Array.isArray(DB[data.object])) { DB[data.object] = []; } if (this.has(data)) { this.remove(data, callback); } else { delete data.bookmark; DB[data.object].unshift(data); DB[data.object][data.resId] = DB[data.object][0]; if (typeof callback === 'function') { callback({ type: 'add', data, index: 0 }); } this.#save(); } } } get has() { return (data) => { if (!this.#check(data)) { return false; } const DB = this.#DB; if (Array.isArray(DB[data.object]) && DB[data.object][data.resId]) { return true; } return false; } } get remove() { return (data, callback) => { if (!this.#check(data)) { return false; } if (!this.has(data)) { return false; } const DB = this.#DB; DB[data.object].some((item, index) => { if (data.resId === item.resId) { DB[data.object].splice(index, 1); delete DB[data.object][data.resId]; if (typeof callback === 'function') { callback({ type: 'remove', data: item, index }); } this.#save(); return true; } }); } } } class Y { #KEY = { state: 'y-app-state' }; get name() { return '易用云'; } get desc() { return '让易搭云更易用'; } get author() { return 'Jack.Chan'; } get path() { return window.location.pathname + window.location.search; } get query() { //return new URLSearchParams(window.location.search.substr(1)); return new URLSearchParams(window.location.search.substr(1) +'&'+ (window.location.hash.split('?')[1] || '')); } #STATE = { pagesize: 5, worktime: '9:00', involved: false, types: {} }; get state() { return this.#STATE; } set state(state) { return this.#STATE = { ...state }; } get saveState() { return () => { window.localStorage.setItem(this.#KEY.state, JSON.stringify(this.state)); } } get loadState() { return () => { let state = window.localStorage.getItem(this.#KEY.state); if (state) { try { state = JSON.parse(state); if (typeof state !== 'object') { state = {} } } catch (ex) { console.warn(ex); } } else { state = {}; } this.state = { ...this.state, ...state }; return state; } } get setState() { return (state, callback) => { if (typeof state === 'object') { Object.keys(state).forEach((key) => { this.state.types[key] = state[key]; }); } if (typeof callback === 'function') { callback(state); } } } get USER() { return USER_INFO.get(); } $app = null; $fetch = $fetch; // QUICK NAV #NAVS = { render() { const navs = [ { text: '流程中心', value: `view=${ encodeURIComponent(JSON.stringify({"name":"流程中心","context":{"flowMenuKey":"doing"},"tag":"ProcessCenter","type":"pageAction"})) }&workspace=U3VZYR` }, { text: '产品线', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=ias8ps5cdm6' }, { text: '项目立项', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=c8ynvsupd5b' }, { text: '发版记录', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=cdumw3k4xqc' }, { text: '需求', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=ftrx43n3g8y' }, { text: '研发任务', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=vzbycr4u6ka' }, { text: '部门任务', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=vzbycr4u6ka' }, { text: '缺陷', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=pia9dfzpjtk' }, { text: '登记工时', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=c4x9y67hvrq' }, { text: '项目月度工时审批', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=mtthhhkguwt' }, { text: '研发月度工时审批', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=scbvpqcicvh' }, { text: '成员工时统计', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=uzbqewzki9w' }, { text: '项目工时统计', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=ytgcs54t2kr' }, { text: '项目成员工时统计', value: 'rootMenu=9959e9c7253340ad9f3cfbc80f05302d&menu=hryqnct76hf' }, { text: 'OA审批', value: 'rootMenu=d27b033dede44c8a9d477041e9edb35d&menu=b5b5yeennmf' }, { text: 'BOSS', value: 'rootMenu=188eebdafa2e411ead5bc02b07a73589&menu=xv6xg7jxhkj' }, { text: '销冠合同审批', value: 'rootMenu=860b3fef58a64bf2aae43343ed6c61ee&menu=jy86kvtiyh3' }, { text: '通讯录', value: 'rootMenu=00360e47fc474f74a814fc270a66b415&menu=eyvuzzuk7k8' }, { text: '易搭云支持平台', value: 'rootMenu=e65fd0c54a0148feb7cbcd85ad3d2297&menu=sfeaduyrta5' } ]; return ` <ul class="y-app-quick-nav"> ${ navs.map((item, index) => { return `<li class="y-app-quick-nav__item"><a class="y-app-btn y-app-btn__small" primary href="#/home?${ item.value }">${ item.text }</a></li>`; }).join('') } </ul> `.trim(); } } // 收藏夹 BOOKMARKS = null; // 参与人选择器 PLAYERS = null; // 分享按钮 BTN_SHARE = null; // 分页 #PAGE_SIZES = [ { value: 5, selected: true }, { value: 10 }, { value: 20 }, { value: 30 }, { value: 50 }, { value: 100 }, { value: 200 } ]; // 视图: 对象名、视图编号、查询参数、模板渲染器、数据 #VIEWS = [ { name: '需求', object: 'eg68i5r43aq', viewNumber: 'baz6tzfuvkf', // 审批流 context: { flowFlag: true }, checked: true, records: [], render: (view, records, options) => { options = { from: 'search', ...options }; if (!view || !records || !records.length) { return ''; } return ` <table class="y-app-table"> <caption class="y-app-table__caption">${ view.name }</caption> <colgroup> <col style="width: 40px;" /> <col style="width: 40px;" /> <col style="width: auto;min-width: 400px;max-width: 900px;" /> <col style="width: 100px;" /> <col style="width: 160px;" /> <col style="width: 140px;" /> <col style="width: 140px;" /> <col style="width: auto;" /> </colgroup> ${ records.map((item, index) => { if (!item.bookmark && !item.object) { item.bookmark = { object: view.object, viewNumber: view.viewNumber, project: item[view.object +'Header_f_zc8nx8Name'], name: item[view.object +'Header_f_h8bqqj'] || item[view.object +'Header_name'], resId: item[view.object +'Header_id'], creator: item[view.object +'Header_creatorName'], players: renderPlayers(item[view.object +'Header_f_b7vp4dName']), createTime: formatDate(item[view.object +'Header_createTime']), updateTime: formatDate(item[view.object +'Header_updateTime']), devStatus: item[view.object +'Header_f_giqar8Name'], priority: item[view.object +'Header_f_d37i79Name'], }; item.bookmark = trimObject(item.bookmark); if (view.context) { item.bookmark.context = view.context; } item.bookmark.title = (item.bookmark.project ? `【${ item.bookmark.project }】` : '') + item.bookmark.name; item.bookmark.url = renderLinkHref(item.bookmark); for (var prop in item.bookmark) { item[prop] = item.bookmark[prop]; } }; item.starred = this.BOOKMARKS.has(item); return ` <tr> <td> <a class="y-app-btn y-app-btn-icon y-app-action" data-from="${ options.from }" data-action="prevent.star" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }" title="${ item.starred ? '取消收藏' : '收藏' }">${ ICONS[item.starred ? 'starred' : 'star'] }</a> </td> <td> <!-- <a target="_blank" href="${ item.url }" class="y-app-btn y-app-btn-icon y-app-action" data-action="prevent.copy" data-project="${ item.project }" data-name="${ item.name }" data-title="${ item.title }" data-from="${ options.from }" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }" title="复制链接">${ ICONS.copy }</a> --> <a target="_blank" href="${ item.url }" class="y-app-btn y-app-btn-icon y-app-action" data-action="prevent.copy" data-project="${ item.project }" data-name="${ item.name }" data-title="${ item.title }" title="复制链接">${ ICONS.copy }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-link y-app-action" data-from="${ options.from }" data-action="prevent.openDrawer" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }">${ item.title }</a> </td> <td><span title="创建人:${ item.creator } 参与人:${ item.players }">${ item.creator }</span></td> <td><span title="创建时间:${ item.createTime } 更新时间:${ item.updateTime }">${ item.updateTime }</span></td> <td><span title="需求状态">${ item.devStatus }</span></td> <td><span title="优先级">${ item.priority }</span></td> <td> </td> </tr> `.trim(); }).join('') } </table> `.trim(); }, params(query) { const params = { "params": { "object": "eg68i5r43aq", "viewType": "viewList", "size": query.size || 50, "page": query.page || 1, "search": { "type": "every", "fields": [ "eg68i5r43aqHeaderName", "moch002vze6", "fnse19vmu5t", "s0nvbqzlu58", "g8qcmno34ix", "7h90amrzdhu", "kntb9eao69o", "k3979lviw8g", "ejnq8nbp1ks", "eg68i5r43aqHeaderStatus" ], "value": query.keyword || '' }, "fields": [ "eg68i5r43aqHeaderName", "moch002vze6", "fnse19vmu5t", "s0nvbqzlu58", "5fftccbn4vn", "g8qcmno34ix", "7h90amrzdhu", "kntb9eao69o", "k3979lviw8g", "4i4hooso8xw", "9i7p66yp7hj", "prpqzpxifvy", "ejnq8nbp1ks", "eg68i5r43aqHeaderStatus" ], "filter": { "rel": "and", "rules": [] }, "summary": [], "sort": [ { "field": "eg68i5r43aqHeaderCreateTime", "number": "m81dt0b9u16", "order": "descend", "orderType": "DESC" } ], "mobileOptions": null, "context": {} }, "context": {} }; // 与我有关的 if (query.involved) { params.params.filter = { "rel": "and", "rules": [ { "number": "w0j1vpyrui4", "rel": "or", "rules": [ { "number": "ybugz2uwya6", "lType": "field", "lValue": [ "eg68i5r43aqHeader", "fnse19vmu5t" ], "op": "in", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] }, { "number": "ztg1twd9r02", "lType": "field", "lValue": [ "eg68i5r43aqHeader", "7ft4nvinhbs" ], "op": "contains", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] }, { "number": "am4fq8ostla", "lType": "field", "lValue": [ "eg68i5r43aqHeader", "eg68i5r43aqHeaderCreator" ], "op": "in", "rType": "constant", "rValue": [ // "1594888324594606163" USER_INFO.get('id') ] } ] }, { "number": "lva1dayvzg7", "rel": "and", "rules": [ { "number": "x29396d8gal", "lType": "field", "lValue": [ "eg68i5r43aqHeader", "k3979lviw8g" ], "op": "in", "rType": "constant", "rValue": [ "rs3rh8da323", "e0vnqk6rvy5", "5bn9ayf0sgk", "zbs0i8e1hdz", "56g8zm7gkdo", "o49jkiqkmnv", // "w7t6sisqu31", // 正常关闭 "3gb5v85bprv", "9sme879pbvo" ] } ] } ] }; } return params; }, }, { name: '缺陷', object: 'jkubb5t4pj7', viewNumber: 'prgp74dayd5', context: { flowFlag: true }, checked: true, render: (view, records, options) => { options = { from: 'search', ...options }; if (!view || !records || !records.length) { return ''; } return ` <table class="y-app-table"> <caption class="y-app-table__caption">${ this.#VIEWS[view.object].name }</caption> <colgroup> <col style="width: 40px;" /> <col style="width: 40px;" /> <col style="width: auto;min-width: 400px;max-width: 900px;" /> <col style="width: 100px;" /> <col style="width: 160px;" /> <col style="width: 140px;" /> <col style="width: 140px;" /> <col style="width: auto;" /> </colgroup> ${ records.map((item, index) => { if (!item.bookmark && !item.object) { item.bookmark = { object: view.object, viewNumber: view.viewNumber, project: item[view.object +'Header_f_tavfi9Name'], name: item[view.object +'Header_f_k8qz5t'] || item[view.object +'Header_name'], resId: item[view.object +'Header_id'], creator: item[view.object +'Header_creatorName'], players: renderPlayers(item[view.object +'Header_f_tx98jjName']), createTime: formatDate(item[view.object +'Header_createTime']), updateTime: formatDate(item[view.object +'Header_updateTime']), devStatus: item[view.object +'Header_f_etietbName'], priority: item[view.object +'Header_f_bw7iwcName'], }; item.bookmark = trimObject(item.bookmark); if (view.context) { item.bookmark.context = view.context; } item.bookmark.title = (item.bookmark.project ? `【${ item.bookmark.project }】` : '') + item.bookmark.name; item.bookmark.url = renderLinkHref(item.bookmark); for (var prop in item.bookmark) { item[prop] = item.bookmark[prop]; } }; item.starred = this.BOOKMARKS.has(item); return ` <tr> <td> <a class="y-app-btn y-app-btn-icon y-app-action" data-from="${ options.from }" data-action="prevent.star" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }" title="${ item.starred ? '取消收藏' : '收藏' }">${ ICONS[item.starred ? 'starred' : 'star'] }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-btn y-app-btn-icon y-app-action" data-action="prevent.copy" data-project="${ item.project }" data-name="${ item.name }" data-title="${ item.title }" title="复制链接">${ ICONS.copy }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-link y-app-action" data-from="${ options.from }" data-action="prevent.openDrawer" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }">${ item.title }</a> </td> <td><span title="创建人:${ item.creator } 参与人:${ item.players }">${ item.creator }</span></td> <td><span title="创建时间:${ item.createTime } 更新时间:${ item.updateTime }">${ item.updateTime }</span></td> <td><span title="缺陷状态">${ item.devStatus }</span></td> <td><span title="优先级">${ item.priority }</span></td> <td> </td> </tr> `.trim(); }).join('') } </table> `.trim(); }, params(query) { const params = { "params": { "object": "jkubb5t4pj7", "viewType": "viewList", "size": query.size || 50, "page": query.page || 1, "search": { "type": "every", "fields": [ "rq8rbzr8mtx", "zii2oihcraf", "xjlih2lj64m", "6s6pnhzilf3", "n3ej7s7ksuq", "jkubb5t4pj7HeaderCreator", "anefrl25i1a" ], "value": query.keyword || '' }, "fields": [ "rq8rbzr8mtx", "zii2oihcraf", "xjlih2lj64m", "6s6pnhzilf3", "n3ej7s7ksuq", "jkubb5t4pj7HeaderCreator", "jkubb5t4pj7HeaderCreateTime", "anefrl25i1a" ], "filter": { "rel": "and", "rules": [] }, "summary": [], "sort": [ { "field": "jkubb5t4pj7HeaderCreateTime", "number": "mj2e3fjgeyu", "order": "descend", "orderType": "DESC" } ], "mobileOptions": null, "context": {} }, "context": {} }; // 与我有关的 缺陷 if (query.involved) { params.params.filter = { "rel": "and", "rules": [ { "number": "gyzggqlk5u1", "rel": "or", "rules": [ { "number": "gjvcsiln78q", "lType": "field", "lValue": [ "jkubb5t4pj7Header", "jkubb5t4pj7HeaderCreator" ], "op": "in", "rType": "constant", "rValue": [ // "1594888324594606163" USER_INFO.get('id') ] }, { "number": "maq433j9400", "lType": "field", "lValue": [ "jkubb5t4pj7Header", "anefrl25i1a" ], "op": "contains", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] }, { "number": "mwzmb66egcc", "lType": "field", "lValue": [ "jkubb5t4pj7Header", "xjlih2lj64m" ], "op": "in", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] } ] }, { "number": "35a5b8esisp", "rel": "and", "rules": [ { "number": "rc9md2gbyb5", "lType": "field", "lValue": [ "jkubb5t4pj7Header", "zii2oihcraf" ], "op": "in", "rType": "constant", "rValue": [ "hovq5gukui3", "hyreb65tq3l", "99gbf8mrn0j", "yha99te9o7j", "lvwjsakiu6v" // "lahf9eis5sz" // 正常结束 ] } ] } ] }; } return params; }, }, { name: '研发任务', object: 'uzze6x8nxxz', viewNumber: 'zgezk76v77m', // context: { flowFlag: true }, checked: true, render: (view, records, options) => { options = { from: 'search', ...options }; if (!view || !records || !records.length) { return ''; } return ` <table class="y-app-table"> <caption class="y-app-table__caption">${ view.name }</caption> <colgroup> <col style="width: 40px;" /> <col style="width: 40px;" /> <col style="width: auto;min-width: 400px;max-width: 900px;" /> <col style="width: 100px;" /> <col style="width: 160px;" /> <col style="width: 140px;" /> <col style="width: 140px;" /> <col style="width: auto;" /> </colgroup> ${ records.map((item, index) => { if (!item.bookmark && !item.object) { item.bookmark = { object: view.object, viewNumber: view.viewNumber, project: item[view.object +'Header_f_x6k7veName'], name: item[view.object +'Header_f_qg8xig'] || item[view.object +'Header_name'], resId: item[view.object +'Header_id'], creator: item[view.object +'Header_creatorName'], players: renderPlayers(item[view.object +'Header_f_uqukrwName']), createTime: formatDate(item[view.object +'Header_createTime']), updateTime: formatDate(item[view.object +'Header_updateTime']), devStatus: item[view.object +'Header_f_r876g4Name'], priority: item[view.object +'Header_f_w2wqevName'], }; item.bookmark = trimObject(item.bookmark); if (view.context) { item.bookmark.context = view.context; } item.bookmark.title = (item.bookmark.project ? `【${ item.bookmark.project }】` : '') + item.bookmark.name; item.bookmark.url = renderLinkHref(item.bookmark); for (var prop in item.bookmark) { item[prop] = item.bookmark[prop]; } }; item.starred = this.BOOKMARKS.has(item); return ` <tr> <td> <a class="y-app-btn y-app-btn-icon y-app-action" data-from="${ options.from }" data-action="prevent.star" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }" title="${ item.starred ? '取消收藏' : '收藏' }">${ ICONS[item.starred ? 'starred' : 'star'] }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-btn y-app-btn-icon y-app-action" data-action="prevent.copy" data-project="${ item.project }" data-name="${ item.name }" data-title="${ item.title }" title="复制链接">${ ICONS.copy }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-link y-app-action" data-from="${ options.from }" data-action="prevent.openDrawer" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }">${ item.title }</a> </td> <td><span title="创建人:${ item.creator } 参与人:${ item.players }">${ item.creator }</span></td> <td><span title="创建时间:${ item.createTime } 更新时间:${ item.updateTime }">${ item.updateTime }</span></td> <td><span title="任务状态">${ item.devStatus }</span></td> <td><span title="优先级">${ item.priority }</span></td> <td> </td> </tr> `.trim(); }).join('') } </table> `.trim(); }, params(query) { const params = { "params": { "object": "uzze6x8nxxz", "viewType": "viewList", "size": query.size || 50, "page": query.page || 1, "search": { "type": "every", "fields": [ "z8fmgy96ijx", "885kt2czitt", "l6veducif7d", "pkegrllxfey", "j0v1yxq1l5y", "odp4x7373wz", "0wqxezfjh9u", "uzze6x8nxxzHeaderCreator" ], "value": query.keyword || '' }, "fields": [ "z8fmgy96ijx", "885kt2czitt", "l6veducif7d", "pkegrllxfey", "j0v1yxq1l5y", "odp4x7373wz", "q93c6g227n6", "0wqxezfjh9u", "uzze6x8nxxzHeaderCreator", "uzze6x8nxxzHeaderCreateTime" ], "filter": { "rel": "and", "rules": [] }, "summary": [], "sort": [ { "field": "uzze6x8nxxzHeaderCreateTime", "number": "jl5fu6lbna2", "order": "descend", "orderType": "DESC" } ], "mobileOptions": null, "context": {} }, "context": {} }; // 与我有关的 研发任务 if (query.involved) { params.params.filter = { "rel": "and", "rules": [ { "number": "x17ylktt0za", "rel": "or", "rules": [ { "number": "bqy2lv1swwr", "lType": "field", "lValue": [ "uzze6x8nxxzHeader", "l6veducif7d" ], "op": "in", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] }, { "number": "w63dar6u7rc", "lType": "field", "lValue": [ "uzze6x8nxxzHeader", "ydc3y16bjzw" ], "op": "contains", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] }, { "number": "92o07r5w4ki", "lType": "field", "lValue": [ "uzze6x8nxxzHeader", "uzze6x8nxxzHeaderCreator" ], "op": "in", "rType": "constant", "rValue": [ // "1594888324594606163" USER_INFO.get('id') ] } ] }, { "number": "nzu45djw3nr", "rel": "and", "rules": [ { "number": "lcuyzo8ytvm", "lType": "field", "lValue": [ "uzze6x8nxxzHeader", "885kt2czitt" ], "op": "in", "rType": "constant", "rValue": [ "012j1zkzcb1", // "kjhop9uygpk", // 已完成 "upuidb76ls8", "i4hz50jso38" ] } ] } ] }; } return params; }, }, { name: '部门任务', object: 'heemdyu3ggi', viewNumber: 'jjh9bh45jea', // context: { flowFlag: true }, checked: false, render: (view, records, options) => { options = { from: 'search', ...options }; if (!view || !records || !records.length) { return ''; } return ` <table class="y-app-table"> <caption class="y-app-table__caption">${ view.name }</caption> <colgroup> <col style="width: 40px;" /> <col style="width: 40px;" /> <col style="width: auto;min-width: 400px;max-width: 900px;" /> <col style="width: 100px;" /> <col style="width: 160px;" /> <col style="width: 140px;" /> <col style="width: 140px;" /> <col style="width: auto;" /> </colgroup> ${ records.map((item, index) => { if (!item.bookmark && !item.object) { item.bookmark = { object: view.object, viewNumber: view.viewNumber, project: '', name: item[view.object +'Header_f_bq54vn'] || item[view.object +'Header_name'], resId: item[view.object +'Header_id'], creator: item[view.object +'Header_creatorName'], players: renderPlayers(item[view.object +'Header_f_axzi2cName']), createTime: formatDate(item[view.object +'Header_createTime']), updateTime: formatDate(item[view.object +'Header_updateTime']), devStatus: item[view.object +'Header_f_bjzbdaName'], type: item[view.object +'Header_f_retjgaName'], priority: item[view.object +'Header_f_ft8ivjName'], }; item.bookmark = trimObject(item.bookmark); if (view.context) { item.bookmark.context = view.context; } item.bookmark.title = (item.bookmark.project ? `【${ item.bookmark.project }】` : '') + item.bookmark.name; item.bookmark.url = renderLinkHref(item.bookmark); for (var prop in item.bookmark) { item[prop] = item.bookmark[prop]; } }; item.starred = this.BOOKMARKS.has(item); return ` <tr> <td> <a class="y-app-btn y-app-btn-icon y-app-action" data-from="${ options.from }" data-action="prevent.star" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }" title="${ item.starred ? '取消收藏' : '收藏' }">${ ICONS[item.starred ? 'starred' : 'star'] }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-btn y-app-btn-icon y-app-action" data-action="prevent.copy" data-project="${ item.project }" data-name="${ item.name }" data-title="${ item.title }" title="复制链接">${ ICONS.copy }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-link y-app-action" data-from="${ options.from }" data-action="prevent.openDrawer" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }">${ item.name }</a> </td> <td><span title="创建人:${ item.creator } 参与人:${ item.players }">${ item.creator }</span></td> <td><span title="创建时间:${ item.createTime } 更新时间:${ item.updateTime }">${ item.updateTime }</span></td> <td><span title="任务状态">${ item.devStatus }</span></td> <td><span title="优先级">${ item.priority }</span></td> <td> </td> </tr> `.trim(); }).join('') } </table> `.trim(); }, params(query) { const params = { "params": { "object": "heemdyu3ggi", "viewType": "viewList", "size": query.size || 50, "page": query.page || 1, "search": { "type": "every", "fields": [ "dmp03a0i2r4", "epi1wxmdd04", "yypr9li882x", "uk5x29bns2z", "trde6pekcxt", "n6abi2jey2b", "heemdyu3ggiHeaderCreator", "wd2ipbnksc1" ], "value": query.keyword || '' }, "fields": [ "dmp03a0i2r4", "epi1wxmdd04", "yypr9li882x", "uk5x29bns2z", "trde6pekcxt", "4sjyfqn7n11", "n6abi2jey2b", "heemdyu3ggiHeaderCreator", "heemdyu3ggiHeaderCreateTime", "wd2ipbnksc1" ], "filter": { "rel": "and", "rules": [] }, "summary": [], "sort": [], "mobileOptions": null, "context": {} }, "context": {} }; // 与我有关的 部门任务 if (query.involved) { params.params.filter = { "rel": "and", "rules": [ { "number": "vr6sdxlcgud", "rel": "or", "rules": [ { "number": "bb3s2x055g0", "lType": "field", "lValue": [ "heemdyu3ggiHeader", "yypr9li882x" ], "op": "in", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] }, { "number": "twjnqnq5m1q", "lType": "field", "lValue": [ "heemdyu3ggiHeader", "heemdyu3ggiHeaderCreator" ], "op": "in", "rType": "constant", "rValue": [ // "1594888324594606163" USER_INFO.get('id') ] }, { "number": "s442b89do2x", "lType": "field", "lValue": [ "heemdyu3ggiHeader", "zqybtgx4h1f" ], "op": "contains", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] } ] }, { "number": "f7e1v2oja5i", "rel": "and", "rules": [ { "number": "pc9y1rs4thh", "lType": "field", "lValue": [ "heemdyu3ggiHeader", "epi1wxmdd04" ], "op": "in", "rType": "constant", "rValue": [ "fu91fdhi7rp", "zjrwyaws59s", // "5lnbqpwb8gc", // 已完成 "z1dkt4efztx" ] } ] } ] }; } return params; }, }, { name: '工时', object: 'wttvmb5t6aj', viewNumber: 'dyvk29qcvan', // context: { flowFlag: true }, checked: false, render: (view, records, options) => { options = { from: 'search', ...options }; if (!view || !records || !records.length) { return ''; } return ` <table class="y-app-table"> <caption class="y-app-table__caption">${ view.name }</caption> <colgroup> <col style="width: 40px;" /> <col style="width: 40px;" /> <col style="width: auto;min-width: 400px;max-width: 900px;" /> <col style="width: 100px;" /> <col style="width: 160px;" /> <col style="width: 140px;" /> <col style="width: 140px;" /> <col style="width: auto;" /> </colgroup> ${ records.map((item, index) => { if (!item.bookmark && !item.object) { item.bookmark = { object: view.object, viewNumber: view.viewNumber, project: item[view.object +'Header_f_umxhcwName'], name: item[view.object +'Header_f_j5uc3d'] || item[view.object +'Header_name'], resId: item[view.object +'Header_id'], creator: item[view.object +'Header_creatorName'], createTime: formatDate(item[view.object +'Header_createTime']), updateTime: formatDate(item[view.object +'Header_updateTime']), // 工作类别 type: item[view.object +'Header_f_yk7nu6Name'], // 任务类别 taskType: item[view.object +'Header_f_vxrv3uName'], // 工作时长 duration: item[view.object +'Header_f_nssifb'], }; item.bookmark = trimObject(item.bookmark); if (view.context) { item.bookmark.context = view.context; } item.bookmark.title = (item.bookmark.project ? `【${ item.bookmark.project }】` : '') + item.bookmark.name; item.bookmark.url = renderLinkHref(item.bookmark); for (var prop in item.bookmark) { item[prop] = item.bookmark[prop]; } }; item.starred = this.BOOKMARKS.has(item); return ` <tr> <td> <a class="y-app-btn y-app-btn-icon y-app-action" data-from="${ options.from }" data-action="prevent.star" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }" title="${ item.starred ? '取消收藏' : '收藏' }">${ ICONS[item.starred ? 'starred' : 'star'] }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-btn y-app-btn-icon y-app-action" data-action="prevent.copy" data-project="${ item.project }" data-name="${ item.name }" data-title="${ item.title }" title="复制链接">${ ICONS.copy }</a> </td> <td> <a target="_blank" href="${ item.url }" class="y-app-link y-app-action" data-from="${ options.from }" data-action="prevent.openDrawer" data-object="${ view.object }" data-index="${ index }" data-id="${ item.resId }">${ item.title }</a> </td> <td><span title="登记人">${ item.creator }</span></td> <td><span title="登记时间:${ item.createTime } 更新时间:${ item.updateTime }">${ item.createTime }</span></td> <td><span title="工作时长">${ item.duration }</span></td> <td><span title="工作类别">${ item.type }</span></td> <!-- <td><span title="任务类别">${ item.taskType }</span></td> --> <td> </td> </tr> `.trim(); }).join('') } </table> `.trim(); }, params(query) { const params = { "params": { "object": "wttvmb5t6aj", "viewType": "viewList", "size": query.size || 50, "page": query.page || 1, "search": { "type": "every", "fields": [ "dpz01mdgyt0", "3t7v5gnb2ex", "l377kywr283", "hivk18of39l", "77aqr706vif", "krmlj1gyytz", "9sgsp65lb5l" ], "value": query.keyword || '' }, "fields": [ "s3yq11rqfg8", "dpz01mdgyt0", "3t7v5gnb2ex", "l377kywr283", "p7gyupeuiu4", "hivk18of39l", "77aqr706vif", "krmlj1gyytz", "9sgsp65lb5l", "8rj5nj8ixbo", "egwokhoyckf" ], "filter": { "rel": "and", "rules": [] }, "summary": [], "sort": [ { "field": "s3yq11rqfg8", "number": "umcedfwmj0k", "order": "descend", "orderType": "DESC" } ], "mobileOptions": null, "context": {} }, "context": {} }; // 与我有关的 我登记 if (query.involved) { params.params.filter = { "rel": "and", "rules": [ { "number": "flqvdo4ufwo", "rel": "and", "rules": [ { "number": "tozq0jfutr8", "lType": "field", "lValue": [ "wttvmb5t6ajHeader", "dpz01mdgyt0" ], "op": "in", "rType": "constant", "rValue": [ { "value": USER_INFO.get('id'), "number": USER_INFO.get('number'), "label": USER_INFO.get('name'), "objectNumber": "sysUser" } ] } ] } ] }; } return params; }, } ]; // 工时视图 #VIEW_MANHOUR = { object: 'wttvmb5t6aj', name: '工时', params(query) { return { "params": { "object": "wttvmb5t6aj", "viewType": "viewList", "size": 50, "page": 1, "search": { "type": "every", "fields": [ "dpz01mdgyt0" ], "value": query.userName || '' }, "fields": [ "wttvmb5t6ajNumber", "s3yq11rqfg8", ], "filter": { "rel": "and", "rules": [] }, "sort": [ { "field": "s3yq11rqfg8", "number": "umcedfwmj0k", "order": "descend", "orderType": "DESC" } ], } }; }, render(data) { data = {today: 0, yestoday: 0, now: '', duration: '', ...data }; data.now = (new Date()).toLocaleString('zh-CN', { hour12: false }); return ` <li title="今日登记工时">今日:${ data.today }小时 <span class="y-app-manhour__countdown" title="刷新倒计时">${ data.countdown }s</span></li> <li title="昨日登记工时">昨日:${ data.yestoday }小时</li> <li title="当前上班时长">${ data.duration }</li> <li title="当前时间">时间:${ data.now }</li> `.trim(); } }; // 成员工时统计视图 #VIEW_MANHOUR_MEMBER = { Users: null, async getUsers() { const parse = (data) => { var users = []; // 上海研发 users['deptId_299686'] = '上海'; // 上海 设计部 users['deptId_290390'] = '上海'; // 上海 产品一组 users['deptId_290391'] = '上海'; // 上海 产品二组 users['deptId_309064'] = '上海'; // 上海 产品三组 users['deptId_290392'] = '上海'; // 上海 产品运营组 users['deptId_290386'] = '上海'; // 上海 数据组 users['deptId_290387'] = '上海'; // 上海 运维组 users['deptId_166892'] = '上海'; // 上海 研发一部 users['deptId_166893'] = '上海'; // 上海 研发二部 users['deptId_166894'] = '上海'; // 上海 前端开发部 // 苏州研发 users['deptId_117148'] = '苏州'; // 苏州 研发中心 users['deptId_117377'] = '苏州'; // 苏州 技术部 users['deptId_216505'] = '苏州'; // 苏州 后端组 users['deptId_216507'] = '苏州'; // 苏州 前端组 users['deptId_117376'] = '苏州'; // 苏州 产品组 // 杭州研发 users['deptId_27119'] = '杭州'; // 杭州 产品一组 users['deptId_27104'] = '杭州'; // 杭州 前端组 users['deptId_27035'] = '杭州'; // 杭州 后端一组 users['deptId_99230'] = '杭州'; // 杭州 后端二组 var locale = null; var user = null; data.forEach((item) => { // console.log('x:', item.sysUserHeader_mainDeptName, item.sysUserHeader_mainDeptNumber) if (item.sysUserHeader_userStateNumber !== 'sys_user_state_deactivate') { locale = users['deptId_'+ item.sysUserHeader_mainDeptNumber]; if (locale) { user = { id: item.id, name: item.sysUserHeader_name, number: item.sysUserHeader_number, deptName: item.sysUserHeader_mainDeptName, deptNumber: item.sysUserHeader_mainDeptNumber, locale }; users.push(user); // group of current user users['user_'+ user.name] = users['user_'+ user.name] || []; users['user_'+ user.name]['user_'+ user.name]= user; users['user_'+ user.name].push(user); // group of mainDeptName users[locale +'_'+ user.deptName] = users[locale +'_'+ user.deptName] || []; users[locale +'_'+ user.deptName]['user_'+ user.name]= user; users[locale +'_'+ user.deptName].push(user); // group of locale users[locale] = users[locale] || []; users[locale]['user_'+ user.name]= user; users[locale].push(user); } } }); return users; }; if (this.Users && this.Users.length) { return Promise.resolve(this.Users); } const params = { "params": { "object": "sysUser", "fields": [ "sysUserHeaderName", "sysUserHeaderDept", "sysUserHeaderPhone", "sysUserHeaderEmail", "sysUserHeaderAvatar", "sysUserHeaderSurnameFirstChar", "sysUserHeaderId", "sysUserHeaderNumber" ], "page": 1, "size": 2000, "sort": [ { "field": "sysUserHeaderSurnameFirstChar", "order": "ascend" } ], "context": { "originId": "1728960441309794304", "originObject": "eg68i5r43aq", "originEntryId": null, "originEntryField": null } }, "context": { "originId": "1728960441309794304", "originObject": "eg68i5r43aq", "originEntryId": null, "originEntryField": null } }; return await $fetch('https://api.yidayun.com/runtime/getList', params).then((res)=>{ // console.log(res.data); this.Users = parse(res.data.records); //console.log('this.Users:', this.Users) return this.Users; }).catch((ex) => { console.error(`[ERROR]`, ex) return ex; }); }, async getManhours(groupby, monthRange) { await this.getUsers(); if (groupby === 'me') { groupby = 'user_'+ USER_INFO.get('name'); } if (groupby === 'all') { groupby = ''; } const users = groupby ? this.Users[groupby] : this.Users; if (!users || !users.length) { console.error(`[ERROR]`, { groupby, monthRange, users }); return; } monthRange = monthRange || [ new Date('2023/12/1 00:00:00').getTime(), new Date('2023/12/30 00:00:00').getTime() ]; const params = { "params": { "chartType": "cross_pivot", "chartSchema": { "dataSource": "wttvmb5t6aj", "dataSourceType": "form", "xDimension": [ { "name": "登记人", // "number": "x1c52gfh2hi", "number": "name", "fieldType": "fieldString", "modelNumber": "wttvmb5t6ajHeader", "required": true, "options": { "listFlag": false }, "field": [ "wttvmb5t6ajHeader", "dpz01mdgyt0Name" ] } ], "yDimension": [ { "name": "工作日期", // "number": "yubsrcxz2d1", "number": "date", "fieldType": "fieldDatetime", "modelNumber": "wttvmb5t6ajHeader", "required": true, "options": { "listFlag": true }, "field": [ "wttvmb5t6ajHeader", "s3yq11rqfg8" ], "group": "date-day" } ], "target": [ { "name": "工时", // "number": "ts0ltoz3dkr", "number": "duration", "fieldType": "fieldInt", "modelNumber": "wttvmb5t6ajHeader", "required": false, "field": [ "wttvmb5t6ajHeader", "p7gyupeuiu4" ], "summaryType": "sum", "caculate": "noneCaculate", "formatter": { "format": "number", "chartType": "cross_pivot", "decimalUnit": 2, "quantityUnit": "none", "unitSuffix": "", "thousandSeparator": false } } ], "sort": [ { // "field": "yubsrcxz2d1", "field": "date", "order": "ascend", "sortType": "char", "number": "f6jrvfcdu7y" } ], "globalFilter": { "number": "39nj4tcpcqj", "rel": "and", "rules": [ { "lType": "field", "lValue": [ "wttvmb5t6ajHeader", "s3yq11rqfg8" ], "number": "skipeho6wr1", "op": "bt", "rType": "constant", rValue: monthRange, /*"rValue": [ // 1696089600000, // 1698767999999 // new Date('2023/10/1 00:00:00').getTime(), // new Date('2023/10/31 00:00:00').getTime(), new Date('2023/12/1 00:00:00').getTime(), new Date('2023/12/30 00:00:00').getTime(), ]*/ } ] }, "relatedConfig": { "targets": [] }, "filterNullFlag": true, "totalCol": true, "totalColConfig": { // "ts0ltoz3dkr": "SUM" "duration": "SUM" }, "totalRow": false, "totalRowConfig": { // "ts0ltoz3dkr": "SUM" "duration": "SUM" }, "showSubTotals": false, "computedFields": [], "computedTargets": [] } }, "context": {} }; return await $fetch('https://api.yidayun.com/report/previewChart', params).then((res) => { const data = { users, dates: {}, manhours: {}, totals: {} }; res.data.totalData.forEach((item) => { data.totals[item.name] = item; }); res.data.chartData.forEach((item) => { data.dates[item.date] = item.date; if (users['user_'+ item.name]) { data.manhours[item.name +'_'+ item.date] = item; } }); // console.log(data); return data; }); }, render(data) { if (!data || !Array.isArray(data.users) || !data.dates || !data.totals) { return ''; } // console.log('data.dates:', data.dates); var item = null; var table = []; var thead = []; var tbody = []; const users = [ ...data.users ]; // 分组排序 users.sort((a, b) => { return (a.locale + a.deptName).localeCompare((b.locale + b.deptName)); }); users.forEach((user, rowIndex) => { user.duration = data.totals[user.name] ? data.totals[user.name].duration || '-' : '-'; // 统计登记工时的天数 user.days = 0; for (var date in data.dates) { item = data.manhours[user.name +'_'+ date] if (item && item.duration !== undefined) { user.days++; } } if (rowIndex === 0) { thead.push(`<tr class="y-app-table__manhour-sticky y-app-table__manhour-row-0">`); thead.push(`<th class="y-app-table__manhour-sticky y-app-table__manhour-col-0"><div class="y-app-table__manhour-cell">姓名</div></th>`); thead.push(`<th class="y-app-table__manhour-sticky y-app-table__manhour-col-1"><div class="y-app-table__manhour-cell">地点 部门</div></th>`); thead.push(`<th class="y-app-table__manhour-sticky y-app-table__manhour-col-2"><div class="y-app-table__manhour-cell" title="登记天数合计">天数</div></th>`); thead.push(`<th class="y-app-table__manhour-sticky y-app-table__manhour-col-3"><div class="y-app-table__manhour-cell" title="工时合计">工时</div></th>`); } tbody.push(`<tr>`); tbody.push(`<td class="y-app-table__manhour-sticky y-app-table__manhour-col-0"><div class="y-app-table__manhour-cell" title="${ (rowIndex + 1) }">${ USER_INFO.get('name') === user.name ? `<b>${ user.name }</b>` : user.name }</div></td>`); tbody.push(`<td class="y-app-table__manhour-sticky y-app-table__manhour-col-1"><div class="y-app-table__manhour-cell">${ user.locale } ${ user.deptName }</div></td>`); tbody.push(`<td class="y-app-table__manhour-sticky y-app-table__manhour-col-2"><div class="y-app-table__manhour-cell">${ user.days }</div></td>`); tbody.push(`<td class="y-app-table__manhour-sticky y-app-table__manhour-col-3"><div class="y-app-table__manhour-cell">${ user.duration }</div></td>`); for (var date in data.dates) { item = data.manhours[user.name +'_'+ date] || {}; item.d = new Date(date.replace(/-/g, '/')); item.dStr = date; item.date = item.d.getDate(); item.dateStr = item.date.toString().padStart(2, 0); item.month = item.d.getMonth() + 1; item.monthStr = item.month.toString().padStart(2, 0); item.year = item.d.getFullYear(); item.day = item.d.getDay(); item.dayStr = ['日','一','二','三','四','五','六'][item.day]; item.isWeekend = item.day === 0 || item.day === 6; item.duration = item.duration || '-'; item.unqualified = !item.isWeekend && (item.duration === '-' || item.duration !== '-' && parseFloat(item.duration) < 8); if (rowIndex === 0) { thead.push(`<th class="${ item.isWeekend ? 'is-weekend' : '' }"><div class="y-app-table__manhour-cell" title="${ item.year }年${ item.month }月${ item.date }日 (星期${ item.dayStr })">${ item.dStr }</div></th>`); } tbody.push(`<td class="${ item.isWeekend ? 'is-weekend' : '' }${ item.unqualified ? ' is-unqualified' : '' }"><div class="y-app-table__manhour-cell" title="${ item.year }年${ item.month }月${ item.date }日 (星期${ item.dayStr })">${ item.duration }</div></td>`); // console.log('item:', item); } if (rowIndex === 0) { thead.push(`<\/tr>`); } tbody.push(`<\/tr>`); }); if (thead.length) { thead.unshift('<thead>'); thead.push('</thead>'); table.push(thead.join('')); } if (tbody.length) { tbody.unshift('<tbody>'); tbody.push('</tbody>'); table.push(tbody.join('')); } if (table.length) { table.unshift('<table class="y-app-table__manhour y-app-table__manhour-striped">'); table.push('</table>'); } return table.join(''); } }; constructor() { console.log(`[OK] 初始化 ...`); this.#VIEWS.forEach((item) => { this.#VIEWS[item.object] = item; this.setState({[item.object]: item.checked}); }); this.loadState(); this.init(); this.BOOKMARKS = new BOOKMARKS(); if (window.top !== window) { this.PLAYERS = new PLAYERS(); this.BTN_SHARE = new BTN_SHARE(); } } // @ api getUserInfo(success) { return new Promise((resolve, reject) => { $fetch('https://api.yidayun.com/account/get-session-info', { context: {}, params: {} }).then((res) => { const data = res.data ? res.data : res; if (data && data.account) { data.id = data.user.id; data.name = data.user.name; data.number = data.user.number; data.phone = data.user.phone; data.companyName = data.workspace.name; data.key = `${ data.workspace.number }-${ data.token }`; data.keyTab = `${ data.key }-CUR_TAB`; data.keyTabs = `${ data.key }-TABS`; USER_INFO.set(data); if (typeof success === 'function') { success(data, res); } resolve(data); } else { console.error(`account info error`, res); reject(res); } }).catch((err) => { console.warn('[WARN]', err); reject(err); }); }); } getManhour() { return new Promise((resolve, reject) => { const userName = USER_INFO.get('name'); const userNumber = USER_INFO.get('number'); const view = this.#VIEW_MANHOUR; const now = new Date(); const data = { userName, userNumber, today: 0, yestoday: 0 }; // data.todayTime = `${ now.getFullYear() }${ (now.getMonth()+1).toString().padStart(2, 0) }${ now.getDate().toString().padStart(2, 0) }`; data.todayTime = `${ now.getFullYear() }${ (now.getMonth()+1) }${ now.getDate() }`; now.setDate(now.getDate()-1); // data.yestodayTime = `${ now.getFullYear() }${ (now.getMonth()+1).toString().padStart(2, 0) }${ now.getDate().toString().padStart(2, 0) }`; data.yestodayTime = `${ now.getFullYear() }${ (now.getMonth()+1) }${ now.getDate() }`; $fetch('https://api.yidayun.com/runtime/getList', view.params({ userName })).then((res) => { const records = res.data?.records || []; let userNumber = ''; let workdate = ''; records.forEach((item) => { userNumber = item[view.object +'Header_creatorNumber']; if (data.userNumber === userNumber) { workdate = new Date(item[view.object +'Header_f_g29exe']).toLocaleString('zh-CN', {hour12: false}).replace(/\//g,'').split(' ')[0]; // console.log('workdate', item[view.object +'Header_f_g29exe'], workdate, 'Header_f_nssifb', item[view.object +'Header_f_nssifb']); if (workdate === data.todayTime) { data.today = parseFloat(data.today) + parseFloat(item[view.object +'Header_f_nssifb']); } if (workdate === data.yestodayTime) { data.yestoday = parseFloat(data.yestoday) + parseFloat(item[view.object +'Header_f_nssifb']); } } }); // console.log('manhour:', data); resolve(data); }).catch((error) => { console.error('[ERROR]', error); reject(data); }); }); } getShareLink(query) { if (typeof query !== 'object') { return Promise.reject('params error'); } return $fetch('https://api.yidayun.com/share/getShareLink', { context: {}, params: { objectNumber: query.object, dataId: query.resId } }).then((res) => { console.log('getShareLink:', res.data); if (typeof res.data === 'object') { query.url = res.data.privateLink || res.data.publicLink || JSON.stringify(res.data); } else { query.url = res.data; } query.resId = query.resId; query.objectNumber = query.object; return query; }).catch((err) => { console.warn('[WARN]', err); return err; }) } // @ utils getRecordByElement = ($el, success, error) => { const VIEWS = this.#VIEWS; const BOOKMARKS = this.BOOKMARKS; const getRecord = ($el) => { const data = { status: true, message: 'ok' }; if (!$el) { data.status = false; data.message = '[ERROR] element not found'; console.error(data.message); return data; } data.from = $el.dataset.from; data.action = $el.dataset.action; if (data.action.indexOf('.') > -1) { data.action = data.action.split('.')[1] || ''; } data.object = $el.dataset.object; data.index = $el.dataset.index; if (data.index !== undefined) { data.index = parseInt(data.index); } // console.log('y-app-action:', data); if (data.object === undefined || data.index === undefined) { data.status = false; data.message = `[ERROR] 参数异常: object: ${ data.object }, index: ${ data.index }`; console.error(data.message); return data; } if (data.from === 'search') { data.record = VIEWS[data.object].records[data.index]; } else { data.record = BOOKMARKS.get(data.object, data.index); } return data; } if (typeof success === 'function') { const data = getRecord($el); if (data.status) { success(data); } else { if (typeof error === 'function') { error(data); } } return data; } else { return new Promise((resolve, reject) => { const data = getRecord($el); if (data.status) { resolve(data); } else { reject(data); } }); } return new Promise((resolve, reject) => { let message = 'record not found'; let record = null; const from = $el.dataset.from; const action = $el.dataset.action; const object = $el.dataset.object; let index = $el.dataset.index; if (index !== undefined) { index = parseInt(index); } // console.log('y-app-action:', from, action, object, index); if (object === undefined || index === undefined) { message = `[ERROR] 参数异常: object: ${ object }, index: ${ index } ` console.error(message); return reject({ message }); } if (from === 'search') { record = VIEWS[object].records[index]; } else { record = BOOKMARKS.get(object, index); } if (typeof record === 'object') { if (typeof callback === 'function') { callback(record); } return resolve(record); } return reject({ message }); }); } getWorkingHours(options) { const defaultOptions = { interval: 0, prefix: undefined, duration: '', before() {}, after() {} } options = Object.assign({}, defaultOptions, options); const base = new Date(); base.setHours(9); base.setMinutes(0); base.setSeconds(0); base.setMilliseconds(0); const getNow = () => { return new Date(); // return new Date('2023/10/19 13:10:12'); // return new Date('2023/10/19 12:30:12'); } const current = new Date(); if (base.getHours() - current.getHours() > 2) { base.setDate(base.getDate()-1); } const calc = function() { if (typeof options.before === 'function') { options.before(options, this); } const now = getNow(); const start = new Date(base.getTime()); // reset start time start.setMinutes(0); start.setSeconds(0); start.setMilliseconds(0); // 9点 上班 if (options.start == '9:00') { start.setMinutes(0); } // 9点30分 上班 if (options.start == '9:30') { start.setMinutes(30); } // 午餐时间 不计时 if (now.getHours() == 12) { now.setHours(12); now.setMinutes(0); now.setSeconds(0); now.setMilliseconds(0); } // 13点开始上班,减去 午餐时间 1小时 if (now.getHours() > 12) { now.setMinutes(now.getMinutes() - 60); } let diffText = []; if (start < now) { var diff = now.getTime() - start.getTime(); const days = Math.floor(diff / (24 * 3600 * 1000)); // 时 diff = diff % (24 * 3600 * 1000); const hours = Math.floor(diff / (3600 * 1000)); // 分 diff = diff % (3600 * 1000); const minutes = Math.floor(diff / (60 * 1000)); // 秒 diff = diff % (60*1000); const seconds = Math.round(diff / 1000); diffText.push(hours +'小时'); diffText.push(minutes +'分钟'); diffText.push(seconds +'秒'); diffText = `${ (options.prefix || '') }${ diffText.join(' ') }`; } else { diffText = '上班时间:'+ start.toLocaleTimeString(); } options.duration = diffText; if (typeof options.after === 'function') { options.after(options, this); } } calc(); if (options.interval) { setInterval(function() { calc(); }, options.interval); } } // @ methods // 注入全局样式 injectGlobalStyle() { const cssRules = () => { return ` body>svg{ position: absolute; width: 0px; height: 0px; overflow: hidden; } /* reset layout */ #y-app ~ #root{ padding-top: 80px; } #y-app ~ #root .ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed{ top: 80px !important; } /* 调整分享详情页 高度 */ #y-app ~ #root .eb-share-form-container{ height: calc(100vh - 80px) !important; } /* 调整左侧菜单高度 */ #y-app ~ #root .ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed{ height: calc(100vh - 80px) !important; } ${ window.top !== window ? ` /* iframe 嵌入时 */ ${ window.location.search.indexOf('sb=0') > 0 ? ` /* 调整 容器 背景色 */ #root .ant-pro-basicLayout>.ant-layout .eb-layout-container{ background-color: #fff !important; } /* 隐藏侧边栏 */ #root .ant-pro-basicLayout>.ant-layout>.ant-layout-sider, #root .ant-pro-basicLayout>.ant-layout>div:not(.ant-layout){ display: none !important; } /* 顶部标签 */ /* 隐藏右键菜单 关闭所有标签 */ .ant-dropdown-menu-item-only-child[data-menu-id^="rc-menu-uuid-"][data-menu-id$="-closeAll"]{ display: none; } /* 隐藏首页 tab 标签 */ .eb-layout-container-section>.ant-tabs>.ant-tabs-nav .ant-tabs-tab:not(.ant-tabs-tab-with-remove){ border: 1px solid red; display: none !important; } /* 隐藏首页 tab 内容 */ .ant-tabs-tabpane[id$="-panel-tabhome"][id^="rc-tabs-"]{ display: none !important; } /* 隐藏 tab 标签 LOGO */ #root .eb-home-tabs>.ant-tabs-nav .ant-tabs-extra-content .ant-pro-sider-logo{ display: none; } ` : ''} /* 调整 右侧主题内容 内边距 */ #root .ant-pro-basicLayout>.ant-layout .eb-layout-container-section{ margin: 20px 10px 10px 10px; } /* 调整 tab 标签页内容 内边距 */ #root .ant-pro-basicLayout>.ant-layout .eb-home-tabs-tab{ padding: 0 0 20px 0 !important; } /* 调整 tab 标签 上边距 */ #root .eb-home-tabs>.ant-tabs-nav .ant-tabs-nav-wrap{ padding-top: 3px; } /* 详情页 调整右侧边栏宽度 */ #root .eb-view-wrapper .eb-view-sider-right{ flex: 0 0 300px; width: 300px; margin-right: 10px; } /* 详情页 调整 右侧审批流 外左边距 */ #root .eb-view-wrapper .eb-view-sider-right .eb-flow{ margin-left: -10px; } /* 详情页 调整 内容部分 内边距 */ #root .eb-view-wrapper>.eb-view-form-wrapper>.eb-view-form>.eb-view-content, #root .eb-view-wrapper>.eb-view-form-wrapper>.eb-view-form>.eb-view-list-wrapper{ padding: 0 10px; } /* 详情页 调整 tab 内边距 */ #root .eb-view-wrapper>.eb-view-form-wrapper>.eb-view-form>.eb-view-toolbar{ margin-left: 0; margin-right: 0; padding-left: 10px; padding-right: 10px; } /* 详情页 隐藏 上查、下查 */ #root .eb-view-toolbar.eb-view-toolbar-form-head>.ant-space.ant-formily-button-group>.ant-space-item>.ant-space.ant-space-horizontal{ display: none !important; } /* 调整 列表页 顶部 试图切换 tab 大小 */ .rc-overflow.eb-view-plans .eb-view-plans-item{ padding-top: 2px !important; padding-bottom: 2px !important; margin-bottom: 0 !important; } ` : '' } /* 重置按钮文字 字重 */ .ant-btn{ font-weight: 500 !important; } /* 重置详情页 当前激活标签样式 */ .ant-tabs-content-top .ant-tabs-tab{ padding-top: 6px !important; padding-bottom: 6px !important; padding-left: 10px !important; padding-right: 10px !important; } .eb-view-toolbar-tabs.ant-tabs>.ant-tabs-nav .ant-tabs-ink-bar{ height: 4px !important; bottom: 0px !important; } .eb-view-toolbar-tabs.ant-tabs>.ant-tabs-nav .ant-tabs-tab+.ant-tabs-tab { margin: 0 0 0 15px !important; } .eb-view-toolbar-tabs.ant-tabs>.ant-tabs-nav .ant-tabs-tab-active{ font-size: 14px !important; } .ant-pro-sider-logo{ align-items: start !important; } /* 重置详情页表单label */ .eb-view-form .ant-formily-item-layout-vertical .ant-formily-item-label{ color: #666 !important; margin-bottom:1px !important; } /* 详情页富文本内容预览/编辑器行高 */ .form-html-editor-preview p, .form-html-editor.form-html-editor-edit .w-e-text-container>.w-e-scroll>div>p{ margin: 0 0 2px 0 !important; line-height: 1.5; } /* 详情页右侧流程 标题文字大小调整 */ .eb-flow-item-node-title .ant-typography-ellipsis, .eb-flow-item-node-title-assign{ font-size: inherit !important; } /* 评论和日志字重调整 */ .eb-comment-list-item-content, .eb-form-sider-log-item-time, .eb-form-sider-log-item-content{ font-weight: inherit !important; } /* 日志 */ .eb-form-sider-log-item{ padding-top: 5px !important; padding-bottom: 5px !important; } .eb-form-sider-log-item-time{ padding-bottom: 0 !important; } .eb-form-sider-log-item-content{ margin-bottom: 0 !important; } /* textarea 最小高度调整 */ .ant-formily-item textarea.ant-input{ min-height: 180px; } /* 重置详情页底部操作按钮位置,改到左边展示 */ .eb-view-toolbar--bottom .eb-view-toolbar-group{ direction: ltr !important; } .eb-view-toolbar--bottom .eb-view-toolbar-group .eb-view-toolbar-overflow-right{ justify-content: left !important; } /* 消息列表样式 */ .eb-message-center-list-item .ant-list-item-meta-title{ margin-bottom: 0 !important; } .eb-message-center-list-item-time{ margin-bottom: 0 !important; margin-top: 0 !important; font-weight: inherit !important; } .eb-message-center-list-item .ant-list-item-meta-description .ant-typography{ font-weight: inherit !important; } /* 移除 联系人左边的小图标 */ .eb-perview-option-tag>.ant-typography-ellipsis{ max-width: none !important; margin-left: auto !important; } .eb-perview-option-tag>.anticon{ display: none !important; } `.trim(); }; const $style = document.createElement('style'); $style.setAttribute('id', 'y-app-style-global'); $style.setAttribute('type', 'text/css'); $style.innerHTML = cssRules(); document.head.appendChild($style); console.log(`[OK] 初始化 注入全局样式`); } // 初始化主视图 initMainView(callback) { const state = this.state; const NAVS = this.#NAVS; const VIEWS = this.#VIEWS; const PAGE_SIZES = this.#PAGE_SIZES; const BOOKMARKS = this.BOOKMARKS; const styles = () => { return ` <style type="text/css"> .y-app-root, .y-app-root *, .y-app-root *:before, .y-app-root *:after{ -webkit-box-sizing: border-box; box-sizing: border-box; } .y-app-root{ --font-family: -apple-system,"PingFang SC","Microsoft YaHei","Helvetica Neue",Helvetica,BlinkMacSystemFont,"Segoe UI","Hiragino Sans GB",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; --font-size: 75%; --color: #333; --background: #fff; --background-hover: #F6F6F6; --background-active: #F2F5F9; --link-color: #348fe4; --h2-background: #F1F1F1; --button-border-color: #e8e8e8; --button-border-color-hover: #e8e8e8; --button-background: #fff; --button-background-hover: #f5f5f5; /* --head-height: 80px; */ --head-height: 103px; --sidebar-width: 220px; --bookmarks-width: 220px; --link-color: #348fe4; } a{ color: var(--link-color); text-decoration: none; } a:hover{ text-decoration: underline; } .y-app-hidden{ display: none !important; } .y-app-hidden-v{ visibility: hidden !important; } a.y-app-btn, a.y-app-btn:hover, a.y-app-btn:focus, a.y-app-btn:active{ text-decoration: none; } .y-app-btn{ display: inline-block; border-width: 1px; border-style: solid; border-color: var(--button-border-color); background-color: var(--button-background); color: var(--color); padding: 5px 15px; border-radius: 3px; cursor: pointer; font-size: inherit; & + .y-app-btn{ margin-left: 8px; } &.y-app-btn__small{ padding: 2px 8px; height: 26px; line-height: 20px; } &:hover{ box-shadow: 0 3px 8px 0 rgba(0,0,0, 0.06); border-color: var(--button-border-color-hover); background: var(--button-background-hover); } &:active{ box-shadow: 0 2px 4px 0 rgba(0,0,0, 0.06); background: rgba(0, 0, 0, 0.06); } &[primary]{ color: #5186f0; } &[warn]{ color: #f98e1b; } &[danger]{ color: #f52743; } &.active{ color: #fff; background-color: #5186f0; } &.success{ color: #fff; background-color: #5eba7d; } /* y-app-btn-icon */ &.y-app-btn-icon{ border: 0; box-shadow: none; padding: 4px 5px; height: auto; line-height: 0; text-align: center; display: inline-block; vertical-align: middle; & svg { pointer-events: none; fill: #595959; &.svg-icon-starred{ fill: #eac54f; } &.svg-icon-check{ fill: #28c940; } } } } .text-center{ text-align: center; } .pull-left{ float: left; } .pull-right{ float: right; } .y-app-root{ margin: 0; color: rgba(0,0,0,.85); font-size: 14px; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji; font-variant: tabular-nums; line-height: 1.5715; background-color: #fff; font-feature-settings: "tnum"; } .y-app-head{ position: fixed; left: 0; top: 0; right: 0; z-index: 999; height: var(--head-height); background-color: #fff; background: rgba(255,255,255,0.85); background: #f9f9f9; border-bottom: 1px solid #d5d5d5; box-shadow: 0 2px 10px rgba(0,0,0,.15); } .y-app-main{ position: absolute; top: 0; right: 0; left: 0; z-index: 888; } .y-app-padded{ padding: 10px; } .y-app-logo{ position: absolute; top: 0; left: 0; margin: 0; padding: 2px 0 0 10px; } .y-app-search{ display: inline-block; vertical-align: top; margin: 0; padding-top: 10px; padding-left: 15px; position: absolute; left: 100px; top: 5px; padding-top: 0; .y-app-search__input{ min-width: 467px; } .y-app-search__submit{ margin-left: 10px; } .y-app-search__options{ padding-top: 6px; padding-right: 20px; display: inline-block; vertical-align: top; } } .y-app-input, .y-app-btn{ display: inline-block; vertical-align: middle; } .y-app-input{ height: 32px; line-height: 32px; padding: 0 5px; border: 1px solid #ccc; } .y-app-btn{ height: 32px; line-height: 32px; padding: 0 15px; cursor: pointer; border-radius: 3px; border: 1px solid #ccc; } .y-app-checkbox, .y-app-checkbox__input, .y-app-checkbox__text .y-app-radio, .y-app-radio__input, .y-app-radio__text{ display: inline-block; } .y-app-checkbox, .y-app-radio{ vertical-align: top; padding-right: 10px; } .y-app-checkbox__input, .y-app-checkbox__text, .y-app-radio__input, .y-app-radio__text{ vertical-align: middle; } .y-app-checkbox__text, .y-app-radio__text{ padding-left: 1px; } .y-app-radio__input{ margin: 3px 2px 3px 3px; } .y-app-action .y-app-checkbox__input, .y-app-action .y-app-checkbox__text, .y-app-action .y-app-radio__input, .y-app-action .y-app-radio__text{ pointer-events: none; } @keyframes drawerFadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } .y-app-drawer{ position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 999; &.active{ .y-app-drawer__backdrop{ height: 100%; opacity: 1; -webkit-transition: none; transition: none; -webkit-animation: drawerFadeIn .3s cubic-bezier(.23,1,.32,1); animation: drawerFadeIn .3s cubic-bezier(.23,1,.32,1); } .y-app-drawer__container{ -webkit-transform: translateX(0); transform: translateX(0); } } .y-app-drawer__backdrop{ height: 0; position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 55; background: rgba(0,0,0,.45); opacity: 0; -webkit-transition: opacity .3s linear,height 0s ease .3s; transition: opacity .3s linear,height 0s ease .3s; } .y-app-drawer__container{ box-shadow: -6px 0 16px -8px rgba(0,0,0,.08), -9px 0 28px rgba(0,0,0,.05), -12px 0 48px 16px rgba(0,0,0,.03); position: absolute; top: 0; right: 0; bottom: 0; z-index: 99; width: 80%; max-width: 1200px; min-width: 980px; -webkit-transform: translateX(100%); transform: translateX(110%); -webkit-transition: box-shadow .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1); transition: box-shadow .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1); transition: transform .3s cubic-bezier(.23,1,.32,1),box-shadow .3s cubic-bezier(.23,1,.32,1); transition: transform .3s cubic-bezier(.23,1,.32,1),box-shadow .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1); } .y-app-drawer__head{ height: 50px; background-color: #efeff4; position: relative; z-index: 77; } .y-app-drawer__title{ font-size: 14px; margin: 0; padding-left: 110px; padding-top: 15px; display: inline-block; text-overflow: ellipsis; overflow: hidden; max-width: 95%; word-break: keep-all; white-space: nowrap; } .y-app-drawer__btn-close{ position: absolute; top: 0; left: 0; bottom: 0; border: 0; border-radius: 0; padding-left: 8px; padding-right: 8px; min-height: 50px; min-width: 54px; line-height: normal; } .y-app-btn__copy{ position: absolute; top: 50%; left: 60px; transform: translateY(-50%); } .y-app-drawer__main{ position: relative; z-index: 77; background: #fff; height: calc(100vh - 50px); } .y-app-drawer__iframe{ position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%; } } .y-app-search__bookmarks{ position: fixed; top: var(--head-height); bottom: 0; left: 0; z-index: 9; width: var(--bookmarks-width); background: #eee; overflow: hidden; &:hover{ width: 560px; overflow: visible; } } .y-app-search__bookmarks-container{ min-width: 1200px; overflow: auto; background: #fff; } .y-app-search__result{ /* margin-left: var(--bookmarks-width); */ padding: 15px; } /* 工时筛选 */ .y-app-manhour__filter{ position: fixed; top: var(--head-height); left: 0; right: 0; z-index: 9; height: 60px; padding-top: 18px; padding-left: 20px; padding-right: 20px; background: #fff; } .y-app-manhour__filter-item{ display: inline-block; vertical-align: middle; padding-right: 15px; } .y-app-manhour__filter-item .y-app-radio{ padding-right: 0; } .y-app-manhour__result{ position: relative; z-index: 3; margin-top: 60px; padding: 0 20px 20px 20px; } /* 工时表格 */ .y-app-table__manhour{ table-layout: fixed; border-collapse: collapse; border-spacing: 0; font-size: 14px; } .y-app-table__manhour, .y-app-table__manhour th, .y-app-table__manhour td{ padding: 0; } .y-app-table__manhour th, .y-app-table__manhour td{ white-space: nowrap; min-width: 40px; line-height: 20px; } .y-app-table__manhour th small, .y-app-table__manhour td small{ font-weight: normal; } .y-app-table__manhour th:not(:first-child), .y-app-table__manhour td:not(:first-child){ text-align: center; } .y-app-table__manhour th{ background-color: #eee; } .y-app-table__manhour td{ background-color: #fff; } .y-app-table__manhour tr:hover td{ background-color: #fff1c9 !important; } .y-app-table__manhour-cell{ padding: 3px 5px 2px 5px; border: 1px solid #ccc; margin: -1px; } .y-app-table__manhour-striped > tbody > tr:nth-child(even) > td { background-color: #fafafa; } .y-app-table__manhour-sticky{ position: sticky; } .y-app-table__manhour-sticky.y-app-table__manhour-row-0{ top: 81px; top: 0px; top: 61px; z-index: 7; } .y-app-table__manhour-sticky.y-app-table__manhour-col-0{ left: 21px; left: 1px; min-width: 70px; max-width: 70px; } .y-app-table__manhour-sticky.y-app-table__manhour-col-1{ left: 91px; left: 71px; min-width: 130px; max-width: 130px; text-align: left !important; } .y-app-table__manhour-sticky.y-app-table__manhour-col-2{ left: 222px; left: 202px; min-width: 60px; max-width: 60px; } .y-app-table__manhour-sticky.y-app-table__manhour-col-3{ left: 222px; left: 263px; min-width: 60px; max-width: 60px; } .y-app-table__manhour-col-2, .y-app-table__manhour-striped th.y-app-table__manhour-col-2, .y-app-table__manhour-striped td.y-app-table__manhour-col-2, .y-app-table__manhour-striped > tbody > tr:nth-child(even) > td.y-app-table__manhour-col-2{ background-color: #ffeed4; background-color: #d8eeff; } .y-app-table__manhour-col-3, .y-app-table__manhour-striped th.y-app-table__manhour-col-3, .y-app-table__manhour-striped td.y-app-table__manhour-col-3, .y-app-table__manhour-striped > tbody > tr:nth-child(even) > td.y-app-table__manhour-col-3{ background-color: #ffeed4; background-color: #ffeaca; } .y-app-table__manhour .is-weekend, .y-app-table__manhour-striped > tbody > tr:nth-child(even) > td.is-weekend{ background-color: #d1ffd1; background-color: #e2ffe2; } .y-app-table__manhour .is-unqualified{ color: red; font-weight: bold; } .y-app-table__manhour tr.y-app-table__manhour-row-selected td, .y-app-table__manhour tr.y-app-table__manhour-row-selected:hover td{ background-color: #ffdf9b !important; } .y-app-table{ width: 100%; border-collapse: collapse; font-size: inherit; } .y-app-table + .y-app-table{ margin-top: 25px; } .y-app-table__caption{ font-weight: bold; font-size: 14px; background: #F1F1F1; background: rgba(241,241,241, 0.88); padding: 5px 10px; text-align: left; position: sticky; top: 0; margin-bottom: 5px; } .y-app-table tr:hover>td{ background: var(--background-hover); } .y-app-table tr:active>td{ background: var(--background-active); } .y-app-table th, .y-app-table td { padding: 3px 5px; } .y-app-quick-nav, .y-app-quick-nav__item{ list-style: none; margin: 0; padding: 0; } .y-app-quick-nav{ padding: 10px 10px 0 10px; } .y-app-quick-nav__item{ display: inline-block; margin-right: 5px; margin-bottom: 5px; } /* y-app-view */ .y-app-view{ position: absolute; top: 0; padding-top: var(--head-height); right: 0; bottom: 0; left: 0; min-height: 100vh; z-index: 888; overflow: auto; background: #fff; display: none; &.active{ display: block; } } .y-app-view__container{ height: 100%; } .y-app-view__iframe{ width: 100%; height: 100%; } .y-app-nav{ display: inline-block; vertical-align: top; padding-top: 48px; padding-top: 71px; .y-app-nav__item{ display: inline-block; padding: 5px 10px; min-width: 80px; text-align: center; border-radius: 3px 3px 0 0; &:hover{ background: rgba(0,0,0,.05); text-decoration: none; } &:active{ background: rgba(0,0,0,.1); text-decoration: none; } &.active{ color: #fff; background: #0075ff; background: #2b90ff; } } } /* 右上角工时 */ .y-app-manhour{ position: fixed; top: -1px; right: 0; /* height: var(--head-height); */ height: calc(var(--head-height) - 23px); z-index: 1999; overflow: hidden; min-width: 228px; padding: 4px 10px 10px 10px; background: rgba(255,255,255, 0.88); background: #f9f9f9; background: rgba(249,249,249, 0.9); border-bottom: 1px solid transparent; border-left: 1px solid transparent; transition: all .3s cubic-bezier(.23,1,.32,1); } .y-app-manhour:hover{ height: auto; overflow: visible; background: inherit; box-shadow: -6px 0 16px -8px rgba(0,0,0,.08), -9px 0 28px rgba(0,0,0,.05), -12px 0 48px 16px rgba(0,0,0,.03); border-bottom: 1px solid #d5d5d5; border-left: 1px solid #d5d5d5; box-shadow: 0 2px 10px rgba(0,0,0,.15); } .y-app-manhour__detail, .y-app-manhour__detail>li{ list-style: none; margin: 0; padding: 0; } .y-app-manhour__countdown{ float: right; } .y-app-manhour__detail{ line-height: 18px; } .y-app-manhour__extra{ display: none; } .y-app-manhour__extra, .y-app-manhour__extra>dt, .y-app-manhour__extra>dd{ list-style: none; margin: 0; padding: 0; } .y-app-manhour__extra{ padding-top: 10px; } .y-app-manhour__extra>dt{ font-weight: bold; } .y-app-manhour:hover>.y-app-manhour__extra{ display: block; } .y-app-h2{ font-size: 32px; padding: 50px 0; text-align: center; color: #666; } .y-app-italic{ font-style: italic; } </style> `.trim(); }; const template = () => { let homeQuery = this.query.toString(); homeQuery = homeQuery ? '?'+ homeQuery : ''; const currentYear = new Date().getFullYear(); const currentMonth = new Date().getMonth() + 1; return ` ${ styles() } <div class="y-app-head"> <h2 class="y-app-logo"><a href="/home.html">易用云</a></h2> <nav class="y-app-nav" id="y-app-nav"> <a href="#/home${ homeQuery }" class="y-app-nav__item y-app-action" data-action="prevent.switchView" data-view="home${ homeQuery }">易搭云</a> <a href="#/bookmarks" class="y-app-nav__item y-app-action" data-action="prevent.switchView" data-view="bookmarks">收藏夹</a> <a href="#/search" class="y-app-nav__item y-app-action" data-action="prevent.switchView" data-view="search">需求/缺陷/任务</a> <a href="#/manhour" class="y-app-nav__item y-app-action" data-action="prevent.switchView" data-view="manhour">工时</a> </nav> <form class="y-app-search" id="y-app-search-form" onsubmit="return false"> <div class="y-app-search__inputbox"> <input type="text" id="y-app-search-keyword" class="y-app-input y-app-search__input" placeholder="需求/缺陷/任务关键字 或 姓名"> <button type="submit" class="y-app-btn y-app-search__submit" primary>搜索</button> </div> <div class="y-app-search__options"> ${ VIEWS.map((item) => { return ` <label class="y-app-checkbox y-app-action" data-action="checkbox"> <input type="checkbox" name="y-app-search-types" class="y-app-checkbox__input" value="${ item.object }" ${ state.types[item.object] ? ` checked` : '' }> <span class="y-app-checkbox__text">${ item.name }</span> </label>`; }).join('') } </div> <div class="y-app-search__options"> <label class="y-app-checkbox y-app-action" data-action="checkbox" title="我创建/负责/参与的(不包含 正常结束、已关闭、已完成)"> <input type="checkbox" class="y-app-checkbox__input" value="involved" ${ state.involved ? ` checked` : '' }> <span class="y-app-checkbox__text">与我有关</span> </label> </div> <div class="y-app-search__options"> <select id="y-app-search-size"> ${ PAGE_SIZES.map((item) => { return `<option value="${ item.value }" ${ state.pagesize == item.value ? ` selected="selected"` : '' }>${ item.value }条</option>`.trim(); }).join('') } </select> </div> </form> </div> <div class="y-app-manhour" id="y-app-manhour"> <ul class="y-app-manhour__detail"></ul> <dl class="y-app-manhour__extra"> <dt>设置</dt> <dd>上班时间: <label title="上午 9点" class="y-app-radio y-app-action" data-action="prevent.setWorkTime" data-value="9:00"> <input type="radio" class="y-app-radio__input" name="y-app-manhour-time" value="9:00" ${ state.worktime == '9:00' ? ` checked="checked"` : '' }> <span class="y-app-radio__text">9:00</span> </label> <label title="上午 9点30分" class="y-app-radio y-app-action" data-action="prevent.setWorkTime" data-value="9:30"> <input type="radio" class="y-app-radio__input" name="y-app-manhour-time" value="9:30" ${ !state.worktime || state.worktime == '9:30' ? ` checked="checked"` : '' }> <span class="y-app-radio__text">9:30</span> </label> </dd> </dl> <dl class="y-app-manhour__extra"> <dt>时长计算说明</dt> <dd>13点后 减去午餐时间 1小时</dd> </dl> </div> <div class="y-app-main"> <div class="y-app-view y-app-view__search" data-view="bookmarks"> ${ NAVS.render() } <div class="y-app-search__result" id="y-app-bookmarks"> </div> </div> <div class="y-app-view y-app-view__search" data-view="search"> ${ NAVS.render() } <div class="y-app-search__result" id="y-app-search-result"> <h2 class="y-app-h2 y-app-italic"> SUBLIME / SIMPLE / SMART </h2> <p class="text-center"> <button type="button" class="y-app-btn y-app-action" data-action="prevent.load" primary>瞧一瞧 ~</button> </p> </div> </div> <div class="y-app-view y-app-view__manhour" data-view="manhour"> <div class="y-app-manhour__filter"> <span class="y-app-manhour__filter-item"> <select id="y-app-manhour-year"> ${ [2024,2023,2022].map((item) => { return `<option value="${ item }"${ currentYear == item ? ` selected` : '' }>${ item }年</option>`; }).join('') } </select> </span> <span class="y-app-manhour__filter-item"> <select id="y-app-manhour-month"> ${ [12,11,10,9,8,7,6,5,4,3,2,1].map((item) => { return `<option value="${ item }"${ currentMonth == item ? ` selected` : '' }>${ item }月</option>`; }).join('') } </select> </span> <span class="y-app-manhour__filter-item"> <label class="y-app-radio" data-action="getManhour"> <input type="radio" class="y-app-radio__input" name="y-app-manhour-group-by" value="me" checked> <span class="y-app-radio__text">我的</span> </label> </span> <span class="y-app-manhour__filter-item"> <label class="y-app-radio"> <input type="radio" class="y-app-radio__input" name="y-app-manhour-group-by" value="all"> <span class="y-app-radio__text">全部</span> </label> </span> <span class="y-app-manhour__filter-item"> <label class="y-app-radio"> <input type="radio" class="y-app-radio__input" name="y-app-manhour-group-by" value="上海"> <span class="y-app-radio__text">上海</span> </label> </span> <span class="y-app-manhour__filter-item"> <label class="y-app-radio"> <input type="radio" class="y-app-radio__input" name="y-app-manhour-group-by" value="杭州"> <span class="y-app-radio__text">杭州</span> </label> </span> <span class="y-app-manhour__filter-item"> <label class="y-app-radio"> <input type="radio" class="y-app-radio__input" name="y-app-manhour-group-by" value="苏州"> <span class="y-app-radio__text">苏州</span> </label> </span> <span class="y-app-manhour__filter-item"> <button type="button" class="y-app-btn y-app-action" primary data-action="prevent.viewManhours">查看</button> </span> <span class="y-app-manhour__filter-item"> <button type="button" class="y-app-btn y-app-action" data-action="prevent.copyManhours" title="复制报表">复制</button> </span> </div> <div class="y-app-manhour__result" id="y-app-manhour-result"> <h2 class="y-app-h2 y-app-italic"> 成员工时统计 </h2> </div> </div> </div> `.trim(); } var $app = document.createElement('y-app'); $app.setAttribute('id', 'y-app'); if (document.body.children.length) { document.body.insertBefore($app, document.body.children[0]); } else { document.body.appendChild($app); } $app.$shadow = $app.attachShadow({ mode: 'open' }); $app.$root = document.createElement('div'); $app.$root.className = 'y-app-root'; $app.$root.innerHTML = template().trimHTML(); // $app.$root.addEventListener('click', (event) => { // event.stopPropagation(); // }); // 工时报表视图 $app.$manhourYear = $app.$root.querySelector('#y-app-manhour-year'); $app.$manhourMonth = $app.$root.querySelector('#y-app-manhour-month'); $app.$manhourResult = $app.$root.querySelector('#y-app-manhour-result'); $app.getManhoursFormData = () => { const data = {}; data.year = $app.$manhourYear.value; data.month = $app.$manhourMonth.value; data.groupby = $app.$root.querySelector('input[type="radio"][name="y-app-manhour-group-by"]:checked')?.value; return data; } // 工时 $app.$manhour = $app.$root.querySelector('#y-app-manhour'); $app.$manhour.$detail = $app.$manhour.querySelector('.y-app-manhour__detail'); $app.updateManhour = () => { const VIEW_MANHOUR = this.#VIEW_MANHOUR; const countdownValue = 30; // 30秒倒计时 循环 const data = { countdown: countdownValue, today: 0, yestoday: 0, now: '', duration: '', }; // 拉取已登记的工时 const getManhour = () => { this.getManhour().then((res) => { // console.log('getManhour:', res); data.today = res.today; data.yestoday = res.yestoday; $app.$manhour.$detail.innerHTML = VIEW_MANHOUR.render(data); }); } // 计算上班时长 this.getWorkingHours({ interval: 1000, prefix: '时长:', before: (options) => { // console.log('countdown:', data.countdown); data.countdown--; options.start = state.worktime || '9:30'; const $radio = $app.$manhour.querySelector(`.y-app-radio__input[name="y-app-manhour-time"][value="${ options.start }"]`); if ($radio) { $radio.click(); } }, after: (options) => { data.duration = options.duration; $app.$manhour.$detail.innerHTML = VIEW_MANHOUR.render(data).trimHTML(); if (data.countdown < 1) { data.countdown = countdownValue; getManhour(); } } }); getManhour(); console.log(`[OK] 初始化 工时统计`); } $app.$nav = $app.$root.querySelector('#y-app-nav'); $app.$navs = $app.$nav.querySelectorAll('.y-app-nav__item'); $app.$main = $app.$root.querySelector('.y-app-main'); $app.$views = $app.$root.querySelectorAll('.y-app-view'); // 书签 $app.$bookmarks = $app.$root.querySelector('#y-app-bookmarks'); // 搜索器 $app.$search = $app.$root.querySelector('#y-app-search-form'); $app.$search.$keyword = $app.$root.querySelector('#y-app-search-keyword'); $app.$search.$keyword.value = this.query.get('keyword'); $app.$search.$result = $app.$root.querySelector('#y-app-search-result'); $app.$search.$size = $app.$root.querySelector('#y-app-search-size'); // 搜索 $app.$search.trim = (keyword) => { keyword = (keyword || '').toString().trim(); keyword = keyword.replace(/^【(.*?)】/, '').split('https://')[0].trim(); return keyword; }; $app.$search.search = (keyword, isUpdateInputValue) => { keyword = $app.$search.trim(keyword); // 是否更新搜索关键字 if (isUpdateInputValue) { $app.$search.$keyword.value = keyword; } var query = { // 搜索关键字 keyword, // 每页显示条数 size: parseInt($app.$search.$size.value), // 与我有关的 involved: state.involved } var $types = $app.$search.querySelectorAll('input[name="y-app-search-types"]:checked'); // console.log('$types:', $types); var $fetchs = []; $types.forEach((item) => { ((object) => { if (VIEWS[object]) { // console.log('=>>', VIEWS[object]); $fetchs.push($fetch('https://api.yidayun.com/runtime/getList', VIEWS[object].params(query)).then((res) => { VIEWS[object].records = res.data.records; VIEWS[object].html = VIEWS[object].render(VIEWS[object], res.data.records); return VIEWS[object]; })); } })(item.value); }); Promise.all($fetchs).then((results) => { var html_result = `${ results.map((item) => item.html).join('') }`.trim(); $app.$search.$result.innerHTML = html_result.trimHTML(); // console.log(results); }); } // 搜索按钮 $app.$search.addEventListener('submit', (event) => { event.preventDefault(); const keyword = $app.$search.trim($app.$search.$keyword.value); const query = {}; if (keyword) { query.keyword = keyword; } this.search(keyword, true); this.$router.push({ path: '/search', query }); return false; }); // 页码切换 $app.$search.$size.addEventListener('change', (event) => { // console.log('$app.$search.$size', $app.$search.$size.value); this.state.pagesize = parseInt($app.$search.$size.value); this.saveState(); }); // 抽屉: 打开 $app.openDrawer = (data) => { data = { title: '', url: '', ...data }; if ($app.$drawer) { $app.$root.removeChild($app.$drawer); $app.$drawer = null; } $app.$drawer = document.createElement('div'); $app.$drawer.className = 'y-app-drawer'; $app.$drawer.tabIndex = 0; $app.$drawer.innerHTML = ` <div class="y-app-drawer__backdrop"></div> <div class="y-app-drawer__container"> <div class="y-app-drawer__head"> <button type="button" class="y-app-btn y-app-drawer__btn-close">${ ICONS.close }</button> <a target="_blank" href="${ data.url || 'javascript:void(0)' }" class="y-app-btn y-app-btn-icon y-app-btn__copy y-app-action" data-action="prevent.copy" data-project="${ data.project }" data-name="${ data.name }" data-title="${ data.title }" title="复制链接">${ ICONS.copy }</a> <h3 class="y-app-drawer__title">${ data.title }</h3> </div> <div class="y-app-drawer__main"> <iframe class="y-app-drawer__iframe" frameborder="0" scrolling="no" src="${ data.url }&sb=0"></div> </div> </div> `.trim().trimHTML(); $app.$drawer.addEventListener('keydown', (event) => { event.stopPropagation(); console.log('drawer.keydown', event); if (event.keyCode === 27) { $app.closeDrawer(); } }); $app.$drawer.$backdrop = $app.$drawer.querySelector('.y-app-drawer__backdrop'); $app.$drawer.$backdrop.addEventListener('click', (event) => { event.preventDefault(); // event.stopPropagation(); $app.closeDrawer(); }); $app.$drawer.$container = $app.$drawer.querySelector('.y-app-drawer__container'); $app.$drawer.$container.addEventListener('click', (event) => { event.preventDefault(); // event.stopPropagation(); }); $app.$drawer.$btnClose = $app.$drawer.querySelector('.y-app-drawer__btn-close'); $app.$drawer.$btnClose.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); $app.closeDrawer(); }); // get current userTabs this.userTabs = window.sessionStorage.getItem(USER_INFO.get('keyTabs')); try { this.userTabs = JSON.parse(this.userTabs); if (Array.isArray(this.userTabs)) { // backup to localStorage window.localStorage.setItem(USER_INFO.get('keyTabs'), JSON.stringify(this.userTabs)); // remove tabs window.sessionStorage.removeItem(USER_INFO.get('keyTabs')); } else { this.userTabs = null; } } catch (ex) { console.error(ex); } $app.$root.appendChild($app.$drawer); setTimeout(() => { $app.$drawer.classList.add('active'); $app.$drawer.focus(); }, 10); } // 抽屉: 关闭 $app.closeDrawer = () => { if (!$app.$drawer) { return; } // restore tabs if (this.userTabs && Array.isArray(this.userTabs)) { let currentTabs = window.sessionStorage.getItem(USER_INFO.get('keyTabs')); // merge tabs try { currentTabs = JSON.parse(currentTabs); if (Array.isArray(this.userTabs) && Array.isArray(currentTabs)) { currentTabs = this.userTabs.concat(currentTabs); // console.log('before', currentTabs); // 去除重复标签 let lastResId = null; currentTabs = currentTabs.filter((item) => { if (item.resId !== lastResId) { lastResId = item.resId; return true; } return false; }); // console.log('after', currentTabs); } } catch (ex) { console.warn(ex); } // save tabs if (Array.isArray(currentTabs)) { this.userTabs = JSON.stringify(currentTabs); window.localStorage.setItem(USER_INFO.get('keyTabs'), this.userTabs); window.sessionStorage.setItem(USER_INFO.get('keyTabs'), this.userTabs); } } $app.$drawer.classList.remove('active'); setTimeout(() => { $app.$root.removeChild($app.$drawer); $app.$drawer = null; }, 350); } // 事件处理器 $app.$root.addEventListener('click', (event) => { event.stopPropagation(); const $el = event.target; if ($el && $app.$root.contains($el) && $el.classList.contains('y-app-action')) { let action = $el.dataset.action; if (!action) { return false; } // console.log('action:', action); if (action.startsWith('prevent.')) { event.preventDefault(); } if (action.indexOf('.') > -1) { action = action.split('.')[1] || ''; } switch (action) { case 'openDrawer': this.getRecordByElement($el).then((data) => { $app.openDrawer(data.record); }); break; case 'star': this.getRecordByElement($el).then((data) => { if (data.from === 'search') { BOOKMARKS.add(data.record.bookmark, ({ type }) => { $el.innerHTML = ICONS[type === 'add' ? 'starred' : 'star']; $el.title = type === 'add' ? '取消收藏' : '收藏'; $app.$bookmarks.update(); }); } else { $app.$bookmarks.unstar(data.record.resId); BOOKMARKS.remove(data.record, ({ type }) => { $app.$bookmarks.update(); }); } }); break; case 'copy': let data = { project: '', name: '', url: '', title: '' }; data.project = $el.dataset.project || ''; data.name = $el.dataset.name || ''; data.url = $el.dataset.url || $el.getAttribute('href') || ''; data.title = $el.dataset.title || (data.project ? `【${ data.project }】` : '') + data.name; doCopy(`${ data.title } \n${ data.url }`).then(() => { $el.innerHTML = ICONS.check; setTimeout(() => { $el.innerHTML = ICONS.copy; }, 3000); }); break; case 'setWorkTime': $el.$input = $el.querySelector('input[type="radio"]'); if ($el.$input) { setTimeout(() => { // console.log('setWorkTime', $el.$input.value); this.state.worktime = $el.$input.value; this.saveState(); }, 50); } break; case 'checkbox': $el.$input = $el.querySelector('input[type="checkbox"]'); if ($el.$input) { // $el.$input.checked = $el.$input.checked; setTimeout(() => { // console.log('$input', $el.$input.checked, $el.$input.value); // 与我有关的 checkbox if ($el.$input.value === 'involved') { this.state.involved = $el.$input.checked; } else { this.state.types[$el.$input.value] = $el.$input.checked; } this.saveState(); }, 50); } break; case 'switchView': console.log('switchView:', this.$route, this.$route.path); // console.log('Q:', this.query.toString()); if ($el.dataset.view.startsWith('home') && this.$route.path.startsWith('/home')) { this.$router.push(window.location.hash.substring(1)); $el.hash = window.location.hash; $el.dataset.view = window.location.hash.substring(2); this.homeViewURL = window.location.hash.substring(1); // console.log('homeViewURL:', this.homeViewURL); return; } this.$router.push('/'+ $el.dataset.view); break; case 'load': // console.log('r:', this.$router); $app.$search.search() break; case 'copyManhours': var $table = $app.$manhourResult.querySelector('table'); if (!$table) { return; } $el.setAttribute('disabled', 'disabled'); copyElementContents($table).then(() => { $el.innerText = '复制成功'; setTimeout(() => { $el.innerText = '复制'; $el.removeAttribute('disabled'); }, 3000); }).catch(() => { $el.removeAttribute('disabled'); }); break; case 'viewManhours': if (this.#VIEW_MANHOUR_MEMBER.loading) { return false; } var fd = $app.getManhoursFormData(); fd.start = new Date(`${ fd.year }/${ fd.month }/1 00:00:00`); fd.end = new Date(`${ fd.year }/${ fd.month }/1 00:00:00`); fd.end.setMonth(fd.end.getMonth() + 1); fd.end.setDate(0); fd.monthRange = []; fd.monthRange.push(fd.start.getTime()); fd.monthRange.push(fd.end.getTime()); // console.log('fd:', fd); // console.log('fd:', fd.start.toLocaleString(), ' -> ', fd.end.toLocaleString()); this.#VIEW_MANHOUR_MEMBER.loading = true; $el.innerText = '加载中...'; $app.$manhourResult.innerHTML = `<h2 class="y-app-h2 y-app-italic"> 加载中... </h2>`; this.#VIEW_MANHOUR_MEMBER.getManhours(fd.groupby, fd.monthRange).then((data) => { $app.$manhourResult.innerHTML = this.#VIEW_MANHOUR_MEMBER.render(data); $app.$manhourResult.classNameRowSelected = 'y-app-table__manhour-row-selected'; $app.$manhourResult.$trs = $app.$manhourResult.querySelectorAll('tbody>tr'); $app.$manhourResult.$trs.forEach((item) => { ((tr) => { tr.addEventListener('click', (event) => { if (tr.classList.contains($app.$manhourResult.classNameRowSelected)) { return tr.classList.remove($app.$manhourResult.classNameRowSelected); } $app.$manhourResult.$trs.forEach((_tr) => { _tr && _tr.classList.remove($app.$manhourResult.classNameRowSelected); }); tr.classList.add($app.$manhourResult.classNameRowSelected); }); })(item); }); // console.log('trs', $app.$manhourResult.$trs); }).catch((ex) => { console.error(`[ERROR]`, ex); $app.$manhourResult.innerHTML = `<h2 class="y-app-h2 y-app-italic">出错了, 请重试</h2>` }).finally(() => { $el.innerText = '查看'; this.#VIEW_MANHOUR_MEMBER.loading = false; }); break; default: break; } } }); $app.$bookmarks.unstar = (resId) => { let $el = $app.$search.$result.querySelector(`.y-app-btn-icon[data-id="${ resId }"]`); if ($el) { $el.innerHTML = ICONS.star; $el.title = '收藏'; } } $app.$bookmarks.update = () => { const html = VIEWS.map((view) => { return view.render(view, BOOKMARKS.get(view.object), { from: 'bookmark' }); }).join(''); $app.$bookmarks.innerHTML = html.trimHTML() || `<h2 class="y-app-h2"> ~(^_^)~ </h2>`; } $app.$bookmarks.update(); // favicon $app.$fav = document.createElement('link'); $app.$fav.setAttribute('rel', 'icon'); $app.$fav.setAttribute('href', 'https://www.yidayun.com/images/favicon.png'); document.head.appendChild($app.$fav); // mounted $app.$shadow.appendChild($app.$root); this.$app = $app; this.trigger('beforeMount'); console.log(`[OK] 初始化 易用云 主界面`); if (typeof callback === 'function') { callback(); } } get search() { return (keyword, isUpdateInputValue) => { const { $app } = this; if (!$app) { return; } keyword = (keyword || '').toString().trim(); $app.$search.$keyword.value = keyword; $app.$search.search(keyword, isUpdateInputValue); } } get createHomeView() { return (path) => { const { $app } = this; if (!$app) { return; } path = path || '/home'; // path = path + (path.indexOf('?') > 1 ? '&' : '?'); path = `https://web.yidayun.com${ path || '/home' }`; if (path && path === this.homeViewURL) { console.log('URL 无变化'); return; } if ($app.$homeView) { $app.$main.removeChild($app.$homeView); } this.homeViewURL = path; // console.log('https://web.yidayun.com/home?rootMenu=d27b033dede44c8a9d477041e9edb35d&menu=b5b5yeennmf') // console.log(path) // path = 'https://web.yidayun.com/home?rootMenu=d27b033dede44c8a9d477041e9edb35d&menu=b5b5yeennmf' //$app.$homeNav = $app.$navs[0]; //$app.$homeNav.classList.add('active'); $app.$homeView = document.createElement('div'); $app.$homeView.className = 'y-app-view y-app-view__home active'; $app.$homeView.dataset.view = 'home'; $app.$homeView.innerHTML = ` <div class="y-app-view__container"> <iframe class="y-app-view__iframe" src="${ path }" frameborder="0" scrolling="no"></iframe> </div> `.trimHTML(); $app.$homeView.$frame = $app.$homeView.querySelector('iframe'); $app.$homeView.$frame.addEventListener('load', () => { // this.homeViewURL = path; console.log('iframe loaded', this.homeViewURL); }); $app.$main.appendChild($app.$homeView); } } get switchView() { return (view) => { const { $app } = this; // console.log('@@@', view) if (!$app) { return; } // $app.$navs = $app.$nav.querySelectorAll('.y-app-nav__item'); $app.$views = $app.$root.querySelectorAll('.y-app-view'); let $nav, $view; $app.$navs.forEach((item) => { item.classList.remove('active'); (($el) => { if ($el.dataset.view.split('?')[0] === view) { $nav = $el; } })(item); }); $app.$views.forEach((item) => { item.classList.remove('active'); (($el) => { if ($el.dataset.view.split('?')[0] === view) { $view = $el; } })(item); }); if ($nav) { $nav.classList.add('active'); } if ($view) { $view.classList.add('active'); } // console.log('@@@', view, $view, $nav) } } // 标签页备份器 tabsBackuper() { let tab = null; let tabs = null; const keyTab = USER_INFO.get('keyTab'); const keyTabs = USER_INFO.get('keyTabs'); // remove theme_local_storage_key window.localStorage.removeItem('theme_local_storage_key'); // restore to sessionStorage tab = window.localStorage.getItem('y-app-CUR_TAB'); tabs = window.localStorage.getItem('y-app-TABS'); if (tabs) { window.sessionStorage.setItem(keyTab, tab); window.sessionStorage.setItem(keyTabs, tabs); } // loop backup to localStorage this.timer_backuper = setInterval(() => { tab = window.sessionStorage.getItem(keyTab); tabs = window.sessionStorage.getItem(keyTabs); if (tabs) { window.localStorage.setItem('y-app-CUR_TAB', tab); window.localStorage.setItem('y-app-TABS', tabs); } }, 1500); console.log(`[OK] 初始化 标签页备份器`); } // 屏蔽日志监控&垃圾 block_something_bad() { var block_it = function() { // baidu if (window._agl && window._agl.stop) { // window._agl.push = () => {}; // window._agl.ext._v = '9.9.6'; // window._agl.ext._s = '996'; // window._agl.ext.xAngeliaLogid = '996'; window._agl.stop(); } // aliyun if (window.__bl && window.__bl.removeHook) { window.__bl.removeHook(); if (window.__bl._conf) { window.__bl._conf.debug = true; window.__bl._conf.enableSPA = false; window.__bl._conf.environment = 'dev'; window.__bl._conf.imgUrl = ''; window.__bl._conf.ignoreUrlPath = '/'; } } } setInterval(() => { block_it(); }, 500); block_it(); var clean_it = function() { window.sessionStorage.removeItem('_bl_sid'); for (var key in window.localStorage) { if (key && key.startsWith('fclog_')) { window.localStorage.removeItem(key); } } } setInterval(() => { clean_it(); }, 1000 * 3); clean_it(); console.log(`[OK] 初始化 屏蔽垃圾监控请求`); } get use() { const that = this; return function(plugin) { const args = [ ...arguments ]; args[0] = that; if (plugin && typeof plugin.install === 'function') { // console.log('..', args); plugin.install.apply(that, args); } } } // 事件 #EVENTS = {}; get on() { const that = this const EVENTS = this.#EVENTS; return (eventType, handler) => { if (typeof eventType !== 'string' || typeof handler !== 'function') { return; } EVENTS[eventType] = EVENTS[eventType] || []; EVENTS[eventType].push(handler); } } get off() { const that = this const EVENTS = this.#EVENTS; return (eventType, handler) => { if (typeof eventType !== 'string' || !Array.isArray(EVENTS[eventType])) { return; } if (typeof handler === 'function') { EVENTS[eventType] = EVENTS[eventType].map((item) => { return item !== handler; }); return; } if (handler === undefined) { delete EVENTS[eventType]; } } } get trigger() { const that = this const EVENTS = this.#EVENTS; return function(eventType) { const args = [ ...arguments ]; args[0] = { type: eventType, target: that }; // args.splice(0, 1); if (typeof eventType !== 'string' || !Array.isArray(EVENTS[eventType])) { return; } EVENTS[eventType].forEach((item) => { ((handler) => { // console.log('trigger.handler', handler, args); handler.apply(that, args); })(item); }); } } init() { if (this.inited) { return console.warn(`[WARN] 已经初始化过了`); } this.block_something_bad(); this.injectGlobalStyle(); this.getUserInfo().then((data) => { // 非iframe 才初始化 易用云 主视图 if (window.top === window) { // 回到极速版 const pathname = window.location.pathname; if (pathname.endsWith('/home') || pathname.endsWith('/share/form') || pathname.endsWith('/designer/form') || pathname.endsWith('/app-market')) { window.location.href = window.location.href.replace(/^https\:\/\/web\.yidayun\.com\//, '/home.html#/'); return false; } this.initMainView(() => { // this.tabsBackuper(); this.trigger('mounted'); // 定时更新工时 this.$app.updateManhour(); }); } }).catch((err) => { console.error(err); const pathname = window.location.pathname; if (pathname.startsWith('/login') || pathname.startsWith('/share/form')) { return false; } const $message = document.createElement('div'); $message.innerHTML = ` <center><h1>${ err.errorMessage }</h1></center><hr><center>错误码 (${ err.errorCode })</center> ${ err.errorCode === 403 ? `<center><h3>会话失效,<a rel="opener" style="color:#247fff;" href="https://web.yidayun.com/login?callback=${ encodeURIComponent(window.location.href) }" title="会话失效,需重新登录(不可用)">重新登录(不可用)</a></h3></center>` : '' } `.trimHTML(); document.body.insertBefore($message, document.body.childNodes[0]); }); this.inited = true; } } class ROUTER { #OPTIONS = { base: '', history: false, // hash route: null, routes: [], routesMap: {}, beforeEach: (to, from, next) => { if (typeof next === 'function') { next(); } }, afterEach: (to, from) => {} }; #POPSTATE = []; pushState = ((fn) => { const OPTIONS = this.#OPTIONS; return function(state, title, url) { if (typeof state === 'object') { state = JSON.parse(JSON.stringify(state)); arguments[0] = state; } if (OPTIONS.history) { fn.apply(window.history, arguments); } else { OPTIONS.isForward = true; window.location.hash = url; setTimeout(() => { delete OPTIONS.isForward; }, 100) } } })(window.history.__proto__.pushState); replaceState = ((fn) => { const OPTIONS = this.#OPTIONS; return function(state, title, url) { if (typeof state === 'object') { state = JSON.parse(JSON.stringify(state)); arguments[0] = state; } if (OPTIONS.history) { fn.apply(window.history, arguments); } else { OPTIONS.isForward = true; window.location.replace('#'+ url); setTimeout(() => { delete OPTIONS.isForward; }, 100) } } })(window.history.__proto__.replaceState); constructor(options) { options = { ...options }; if (options.base) { this.#OPTIONS.base = options.base; } if (options.history) { this.#OPTIONS.history = options.history; } if (options.routes) { this.add(options.routes); } if (options.beforeEach) { this.beforeEach(options.beforeEach); } if (options.afterEach) { this.afterEach(options.afterEach); } console.log(`[OK] 初始化 路由 ...`); } get path() { const OPTIONS = this.#OPTIONS; let path = ''; if (OPTIONS.history) { path = window.location.pathname; } else { path = window.location.hash.substr(1).split('?')[0]; } path = path.substr(OPTIONS.base.length); return path; } get query() { const OPTIONS = this.#OPTIONS; let query = ''; if (OPTIONS.history) { query = window.location.search.substr(1); } else { query = window.location.hash.split('?')[1] || ''; } query = new URLSearchParams(query); // const qs = query.toString(); query = Object.fromEntries(query); Object.defineProperty(query, 'toString', { get() { return () => { // return qs; return new URLSearchParams(query).toString(); } } }); return query; } dispatch() { const OPTIONS = this.#OPTIONS; const { beforeEach, afterEach } = OPTIONS; const onChange = (event) => { // console.log('onChange', event); if (event.type === 'hashchange' && OPTIONS.isForward) { // console.error('[isForward]', OPTIONS.isForward); delete OPTIONS.isForward; return; } const form = OPTIONS.route; const to = OPTIONS.routesMap[this.path]; // console.log('onChange.meta', to.meta); // console.log('change.to', to, form) if (to && to.path && to.handler) { to.meta = { ...to.meta }; to.query = this.query; to.qs = to.query.toString(); if (form) { form.meta = { ...form.meta }; } const next = () => { this.#OPTIONS.route = to; to.handler(); if (typeof afterEach === 'function') { afterEach(form, to); } } if (typeof beforeEach === 'function') { beforeEach(to, form, next); } else { next(); } } } // bind event if (OPTIONS.history) { window.addEventListener('popstate', onChange); } else { window.addEventListener('hashchange', onChange); } // start const { routes, routesMap } = OPTIONS; const to = { meta: {}, query: this.query }; let currentRoute = null; if (routesMap[this.path]) { currentRoute = routesMap[this.path]; } else { if (routes.length) { currentRoute = routes[0]; } } if (currentRoute) { to.path = currentRoute.path; to.meta = currentRoute.meta || to.meta; } this.push(to); console.log(`[OK] 初始化 路由 开始监听`); } get beforeEach() { return (fn) => { if (typeof fn === 'function') { this.#OPTIONS.beforeEach = fn; } } } get afterEach() { return (fn) => { if (typeof fn === 'function') { this.#OPTIONS.afterEach = fn; } } } get options() { return this.#OPTIONS; } get add() { return (route, handler) => { if (Array.isArray(route)) { route.forEach((item) => { ((_route) => { this.add(_route, handler); })(item); }); return; } if (typeof route === 'string' && route.length) { route = { path: route }; } if (typeof route === 'object' && typeof handler === 'function') { route.handler = handler || route.handler; } if (typeof route.path === 'string' && route.path.length && typeof route.handler === 'function') { // route.path = this.#OPTIONS.base + route.path; route.meta = { ...route.meta }; if (this.#OPTIONS.routesMap[route.path]) { return console.warn(`[WARN] route has existed`); } this.#OPTIONS.routesMap[route.path] = route; this.#OPTIONS.routes.push(route); } } } get $route() { return this.#OPTIONS.route; } get $routes() { return this.#OPTIONS.routes; } get $router() { return this; } get parse() { return (route) => { if (typeof route === 'string' && route.length) { route = { path: route }; } if (typeof route === 'object' && typeof route.path === 'string' && route.path.length) { route.path = route.path.split('?'); route.qs = route.path[1] || ''; route.path = route.path[0]; route.qs = new URLSearchParams(route.qs).toString(); if (route.query instanceof URLSearchParams) { route.query = route.query.toString(); } else { route.query = new URLSearchParams(route.query).toString(); } route.qs+= (route.qs.length && route.query.length ? '&' : '') + route.query; route.query = Object.fromEntries(new URLSearchParams(route.qs)); // route.qs = (route.qs.length ? '?' : '') + route.qs; Object.defineProperty(route.query, 'toString', { get() { return () => { return route.qs; } } }); return route; } } } get push() { return (to) => { to = this.parse(to); if (!to || !to.path) { return console.log(`[ERROR] route path error`); } const { base, route, routesMap, beforeEach, afterEach } = this.#OPTIONS; if (route && route.path === to.path && route.qs === to.qs) { return; } const currentRoute = routesMap[to.path]; if (currentRoute && currentRoute.path && currentRoute.handler) { const form = route; to.meta = { ...currentRoute.meta }; // console.log('push.meta', to.meta); to.handler = currentRoute.handler; if (form) { form.meta ={ ...form.meta }; } const next = () => { this.pushState(to, form, base + to.path + (to.qs ? '?' : '') + to.qs); this.#OPTIONS.route = to; to.handler(); if (typeof afterEach === 'function') { afterEach(form, to); } } if (typeof beforeEach === 'function') { beforeEach(to, form, next); } else { next(); } } } } get replace() { return (to) => { to = this.parse(to); if (!to || !to.path) { return console.log(`[ERROR] route path error`); } const { base, route, routesMap, beforeEach, afterEach } = this.#OPTIONS; if (route && route.path === to.path && route.qs === to.qs) { return; } const currentRoute = routesMap[to.path]; if (currentRoute && currentRoute.path && currentRoute.handler) { const form = route; to.meta = { ...currentRoute.meta }; // console.log('replace.meta', to.meta); to.handler = currentRoute.handler; if (form) { form.meta ={ ...form.meta }; } const next = () => { this.replaceState(to, form, base + to.path + (to.qs ? '?' : '') + to.qs); this.#OPTIONS.route = to; to.handler(); if (typeof afterEach === 'function') { afterEach(form, to); } } if (typeof beforeEach === 'function') { beforeEach(to, form, next); } else { next(); } } } } get back() { return () => { window.history.back(); } } get reload() { return () => { window.location.reload(); } } get install() { return (app) => { // console.log('install.app', app); if (app && typeof app.use === 'function') { Object.defineProperties(app, { $route: { get: () => { return this.$route } }, $routes: { get: () => { return this.$routes } }, $router: { get: () => { return this.$router } } }); app.on('beforeMount', () => { this.dispatch(); }); } } } } // html 时才注入 if (document.contentType === 'text/html') { const router = new ROUTER({ base: '', routes: [ { path: '/home', meta: { title: '' }, handler() { if (this.query.view) { $Y.createHomeView('/home?view='+ encodeURIComponent(this.query.view) ); //console.log('view:', this.query.view); } else { const qs = this.query.toString(); if (qs.length > 4) { $Y.createHomeView('/home?'+ qs); } else { $Y.createHomeView(); } } $Y.switchView('home'); } }, { path: '/share/form', meta: { title: '' }, handler() { if (this.query.number) { $Y.createHomeView('/share/form?number='+ encodeURIComponent(this.query.number) ); } $Y.switchView('home'); } }, { path: '/share/form/private', meta: { title: '' }, handler() { if (this.query.number) { $Y.createHomeView('/share/form/private?number='+ encodeURIComponent(this.query.number) ); } $Y.switchView('home'); } }, { path: '/designer/form', meta: { title: '' }, handler() { if (this.query.object) { $Y.createHomeView('/designer/form?object='+ encodeURIComponent(this.query.object) ); } $Y.switchView('home'); } }, { path: '/app-market', meta: { title: '' }, handler() { $Y.createHomeView('/app-market?'+ this.qs); $Y.switchView('home'); } }, { path: '/bookmarks', meta: { title: '收藏夹' }, handler() { $Y.switchView('bookmarks'); } }, { path: '/search', meta: { title: '需求/任务/工时' }, handler() { $Y.switchView('search'); } }, { path: '/manhour', meta: { title: '工时' }, handler() { $Y.switchView('manhour'); } }, ] }); router.beforeEach((to, from, next) => { // console.log('beforeEach:', { to, from, next }); // console.log('beforeEach.meta:', to.meta); document.title = (to.meta.title ? to.meta.title +' - ' : '') + $Y.name; next(); }); /*router.afterEach((to, from) => { console.log('afterEach:', { to, from }); });*/ const $Y = new Y(); if (window.top === window) { $Y.use(router); $Y.on('mounted', (event) => { // const app = event.target; if ($Y.path.startsWith('/home?view=')) { window.location.replace('/home.html#/home'+ window.location.search); return; } if ($Y.path.startsWith('/share/form?number=')) { window.location.replace('/home.html#/share/form'+ window.location.search); return; } if ($Y.path.startsWith('/share/form/private?number=')) { window.location.replace('/home.html#/share/form'+ window.location.search); return; } // event.target // console.log('>>>s', this, $Y.path); const keyword = $Y.$route.query.keyword; if (keyword) { $Y.search(keyword, true); } }); } window.$Y = $Y; } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址