befb47e80ac77a75ccf92fd890d675877e209478.svn-base 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. import Vue from 'vue'
  2. import * as api from '@/api/api'
  3. import { isURL } from '@/utils/validate'
  4. import { ACCESS_TOKEN } from '@/store/mutation-types'
  5. import onlineCommons from '@jeecg/antd-online-mini'
  6. export function timeFix() {
  7. const time = new Date()
  8. const hour = time.getHours()
  9. return hour < 9 ? '早上好' : (hour <= 11 ? '上午好' : (hour <= 13 ? '中午好' : (hour < 20 ? '下午好' : '晚上好')))
  10. }
  11. export function welcome() {
  12. const arr = ['休息一会儿吧', '准备吃什么呢?', '要不要打一把 DOTA', '我猜你可能累了']
  13. let index = Math.floor((Math.random()*arr.length))
  14. return arr[index]
  15. }
  16. /**
  17. * 触发 window.resize
  18. */
  19. export function triggerWindowResizeEvent() {
  20. let event = document.createEvent('HTMLEvents')
  21. event.initEvent('resize', true, true)
  22. event.eventType = 'message'
  23. window.dispatchEvent(event)
  24. }
  25. /**
  26. * 过滤对象中为空的属性
  27. * @param obj
  28. * @returns {*}
  29. */
  30. export function filterObj(obj) {
  31. if (!(typeof obj == 'object')) {
  32. return;
  33. }
  34. for ( let key in obj) {
  35. if (obj.hasOwnProperty(key)
  36. && (obj[key] == null || obj[key] == undefined || obj[key] === '')) {
  37. delete obj[key];
  38. }
  39. }
  40. return obj;
  41. }
  42. /**
  43. * 时间格式化
  44. * @param value
  45. * @param fmt
  46. * @returns {*}
  47. */
  48. export function formatDate(value, fmt) {
  49. let regPos = /^\d+(\.\d+)?$/;
  50. if(regPos.test(value)){
  51. //如果是数字
  52. let getDate = new Date(value);
  53. let o = {
  54. 'M+': getDate.getMonth() + 1,
  55. 'd+': getDate.getDate(),
  56. 'h+': getDate.getHours(),
  57. 'm+': getDate.getMinutes(),
  58. 's+': getDate.getSeconds(),
  59. 'q+': Math.floor((getDate.getMonth() + 3) / 3),
  60. 'S': getDate.getMilliseconds()
  61. };
  62. if (/(y+)/.test(fmt)) {
  63. fmt = fmt.replace(RegExp.$1, (getDate.getFullYear() + '').substr(4 - RegExp.$1.length))
  64. }
  65. for (let k in o) {
  66. if (new RegExp('(' + k + ')').test(fmt)) {
  67. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
  68. }
  69. }
  70. return fmt;
  71. }else{
  72. //TODO
  73. value = value.trim();
  74. return value.substr(0,fmt.length);
  75. }
  76. }
  77. // 生成首页路由
  78. export function generateIndexRouter(data) {
  79. let indexRouter = [{
  80. path: '/',
  81. name: 'dashboard',
  82. // component: () => import('@/components/layouts/BasicLayout'),
  83. component: resolve => require(['@/components/layouts/TabLayout'], resolve),
  84. meta: { title: '首页' },
  85. redirect: '/dashboard/analysis',
  86. children: [
  87. ...generateChildRouters(data)
  88. ]
  89. },{
  90. "path": "*", "redirect": "/404", "hidden": true
  91. }]
  92. return indexRouter;
  93. }
  94. // 生成嵌套路由(子路由)
  95. function generateChildRouters (data) {
  96. const routers = [];
  97. for (let item of data) {
  98. let component = "";
  99. if(item.component.indexOf("layouts")>=0){
  100. component = "components/"+item.component;
  101. }else{
  102. component = "views/"+item.component;
  103. }
  104. // eslint-disable-next-line
  105. let URL = (item.meta.url|| '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)) // URL支持{{ window.xxx }}占位符变量
  106. if (isURL(URL)) {
  107. item.meta.url = URL;
  108. }
  109. let componentPath
  110. if(item.component=="modules/online/cgform/OnlCgformHeadList"){
  111. componentPath = onlineCommons.OnlCgformHeadList
  112. }else if(item.component=="modules/online/cgform/OnlCgformCopyList"){
  113. componentPath = onlineCommons.OnlCgformCopyList
  114. }else if(item.component=="modules/online/cgform/auto/OnlCgformAutoList"){
  115. componentPath = onlineCommons.OnlCgformAutoList
  116. }else if(item.component=="modules/online/cgform/auto/OnlCgformTreeList"){
  117. componentPath = onlineCommons.OnlCgformTreeList
  118. }else if(item.component=="modules/online/cgform/auto/erp/OnlCgformErpList"){
  119. componentPath = onlineCommons.OnlCgformErpList
  120. }else if(item.component=="modules/online/cgform/auto/tab/OnlCgformTabList"){
  121. componentPath = onlineCommons.OnlCgformTabList
  122. }else if(item.component=="modules/online/cgform/auto/innerTable/OnlCgformInnerTableList"){
  123. componentPath = onlineCommons.OnlCgformInnerTableList
  124. }else if(item.component=="modules/online/cgreport/OnlCgreportHeadList"){
  125. componentPath = onlineCommons.OnlCgreportHeadList
  126. }else if(item.component=="modules/online/cgreport/auto/OnlCgreportAutoList"){
  127. componentPath = onlineCommons.OnlCgreportAutoList
  128. }else{
  129. componentPath = resolve => require(['@/' + component+'.vue'], resolve)
  130. }
  131. let menu = {
  132. path: item.path,
  133. name: item.name,
  134. redirect:item.redirect,
  135. component: componentPath,
  136. //component: resolve => require(['@/' + component+'.vue'], resolve),
  137. hidden:item.hidden,
  138. //component:()=> import(`@/views/${item.component}.vue`),
  139. meta: {
  140. title:item.meta.title ,
  141. icon: item.meta.icon,
  142. url:item.meta.url ,
  143. permissionList:item.meta.permissionList,
  144. keepAlive:item.meta.keepAlive,
  145. /*update_begin author:wuxianquan date:20190908 for:赋值 */
  146. internalOrExternal:item.meta.internalOrExternal,
  147. /*update_end author:wuxianquan date:20190908 for:赋值 */
  148. componentName:item.meta.componentName
  149. }
  150. }
  151. if(item.alwaysShow){
  152. menu.alwaysShow = true;
  153. menu.redirect = menu.path;
  154. }
  155. if (item.children && item.children.length > 0) {
  156. menu.children = [...generateChildRouters( item.children)];
  157. }
  158. //--update-begin----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
  159. //判断是否生成路由
  160. if(item.route && item.route === '0'){
  161. //console.log(' 不生成路由 item.route: '+item.route);
  162. //console.log(' 不生成路由 item.path: '+item.path);
  163. }else{
  164. routers.push(menu);
  165. }
  166. //--update-end----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
  167. }
  168. return routers
  169. }
  170. /**
  171. * 深度克隆对象、数组
  172. * @param obj 被克隆的对象
  173. * @return 克隆后的对象
  174. */
  175. export function cloneObject(obj) {
  176. return JSON.parse(JSON.stringify(obj))
  177. }
  178. /**
  179. * 随机生成数字
  180. *
  181. * 示例:生成长度为 12 的随机数:randomNumber(12)
  182. * 示例:生成 3~23 之间的随机数:randomNumber(3, 23)
  183. *
  184. * @param1 最小值 | 长度
  185. * @param2 最大值
  186. * @return int 生成后的数字
  187. */
  188. export function randomNumber() {
  189. // 生成 最小值 到 最大值 区间的随机数
  190. const random = (min, max) => {
  191. return Math.floor(Math.random() * (max - min + 1) + min)
  192. }
  193. if (arguments.length === 1) {
  194. let [length] = arguments
  195. // 生成指定长度的随机数字,首位一定不是 0
  196. let nums = [...Array(length).keys()].map((i) => (i > 0 ? random(0, 9) : random(1, 9)))
  197. return parseInt(nums.join(''))
  198. } else if (arguments.length >= 2) {
  199. let [min, max] = arguments
  200. return random(min, max)
  201. } else {
  202. return Number.NaN
  203. }
  204. }
  205. /**
  206. * 随机生成字符串
  207. * @param length 字符串的长度
  208. * @param chats 可选字符串区间(只会生成传入的字符串中的字符)
  209. * @return string 生成的字符串
  210. */
  211. export function randomString(length, chats) {
  212. if (!length) length = 1
  213. if (!chats) chats = '0123456789qwertyuioplkjhgfdsazxcvbnm'
  214. let str = ''
  215. for (let i = 0; i < length; i++) {
  216. let num = randomNumber(0, chats.length - 1)
  217. str += chats[num]
  218. }
  219. return str
  220. }
  221. /**
  222. * 随机生成uuid
  223. * @return string 生成的uuid
  224. */
  225. export function randomUUID() {
  226. let chats = '0123456789abcdef'
  227. return randomString(32, chats)
  228. }
  229. /**
  230. * 下划线转驼峰
  231. * @param string
  232. * @returns {*}
  233. */
  234. export function underLine2CamelCase(string){
  235. return string.replace( /_([a-z])/g, function( all, letter ) {
  236. return letter.toUpperCase();
  237. });
  238. }
  239. /**
  240. * 判断是否显示办理按钮
  241. * @param bpmStatus
  242. * @returns {*}
  243. */
  244. export function showDealBtn(bpmStatus){
  245. if(bpmStatus!="1"&&bpmStatus!="3"&&bpmStatus!="4"){
  246. return true;
  247. }
  248. return false;
  249. }
  250. /**
  251. * 增强CSS,可以在页面上输出全局css
  252. * @param css 要增强的css
  253. * @param id style标签的id,可以用来清除旧样式
  254. */
  255. export function cssExpand(css, id) {
  256. let style = document.createElement('style')
  257. style.type = "text/css"
  258. style.innerHTML = `@charset "UTF-8"; ${css}`
  259. // 清除旧样式
  260. if (id) {
  261. let $style = document.getElementById(id)
  262. if ($style != null) $style.outerHTML = ''
  263. style.id = id
  264. }
  265. // 应用新样式
  266. document.head.appendChild(style)
  267. }
  268. /** 用于js增强事件,运行JS代码,可以传参 */
  269. // options 所需参数:
  270. // 参数名 类型 说明
  271. // vm VueComponent vue实例
  272. // event Object event对象
  273. // jsCode String 待执行的js代码
  274. // errorMessage String 执行出错后的提示(控制台)
  275. export function jsExpand(options = {}) {
  276. // 绑定到window上的keyName
  277. let windowKeyName = 'J_CLICK_EVENT_OPTIONS'
  278. if (typeof window[windowKeyName] != 'object') {
  279. window[windowKeyName] = {}
  280. }
  281. // 随机生成JS增强的执行id,防止冲突
  282. let id = randomString(16, 'qwertyuioplkjhgfdsazxcvbnm'.toUpperCase())
  283. // 封装按钮点击事件
  284. let code = `
  285. (function (o_${id}) {
  286. try {
  287. (function (globalEvent, vm) {
  288. ${options.jsCode}
  289. })(o_${id}.event, o_${id}.vm)
  290. } catch (e) {
  291. o_${id}.error(e)
  292. }
  293. o_${id}.done()
  294. })(window['${windowKeyName}']['EVENT_${id}'])
  295. `
  296. // 创建script标签
  297. const script = document.createElement('script')
  298. // 将需要传递的参数挂载到window对象上
  299. window[windowKeyName]['EVENT_' + id] = {
  300. vm: options.vm,
  301. event: options.event,
  302. // 当执行完成时,无论如何都会调用的回调事件
  303. done() {
  304. // 执行完后删除新增的 script 标签不会撤销执行结果(已产生的结果不会被撤销)
  305. script.outerHTML = ''
  306. delete window[windowKeyName]['EVENT_' + id]
  307. },
  308. // 当js运行出错的时候调用的事件
  309. error(e) {
  310. console.group(`${options.errorMessage || '用户自定义JS增强代码运行出错'}(${new Date()})`)
  311. console.error(e)
  312. console.groupEnd()
  313. }
  314. }
  315. // 将事件挂载到document中
  316. script.innerHTML = code
  317. document.body.appendChild(script)
  318. }
  319. /**
  320. * 重复值验证工具方法
  321. *
  322. * 使用示例:
  323. * { validator: (rule, value, callback) => validateDuplicateValue('sys_fill_rule', 'rule_code', value, this.model.id, callback) }
  324. *
  325. * @param tableName 被验证的表名
  326. * @param fieldName 被验证的字段名
  327. * @param fieldVal 被验证的值
  328. * @param dataId 数据ID,可空
  329. * @param callback
  330. */
  331. export function validateDuplicateValue(tableName, fieldName, fieldVal, dataId, callback) {
  332. if (fieldVal) {
  333. let params = { tableName, fieldName, fieldVal, dataId }
  334. api.duplicateCheck(params).then(res => {
  335. res['success'] ? callback() : callback(res['message'])
  336. }).catch(err => {
  337. callback(err.message || err)
  338. })
  339. } else {
  340. callback()
  341. }
  342. }
  343. /**
  344. * 根据编码校验规则code,校验传入的值是否合法
  345. *
  346. * 使用示例:
  347. * { validator: (rule, value, callback) => validateCheckRule('common', value, callback) }
  348. *
  349. * @param ruleCode 编码校验规则 code
  350. * @param value 被验证的值
  351. * @param callback
  352. */
  353. export function validateCheckRule(ruleCode, value, callback) {
  354. if (ruleCode && value) {
  355. value = encodeURIComponent(value)
  356. api.checkRuleByCode({ ruleCode, value }).then(res => {
  357. res['success'] ? callback() : callback(res['message'])
  358. }).catch(err => {
  359. callback(err.message || err)
  360. })
  361. } else {
  362. callback()
  363. }
  364. }
  365. /**
  366. * 如果值不存在就 push 进数组,反之不处理
  367. * @param array 要操作的数据
  368. * @param value 要添加的值
  369. * @param key 可空,如果比较的是对象,可能存在地址不一样但值实际上是一样的情况,可以传此字段判断对象中唯一的字段,例如 id。不传则直接比较实际值
  370. * @returns {boolean} 成功 push 返回 true,不处理返回 false
  371. */
  372. export function pushIfNotExist(array, value, key) {
  373. for (let item of array) {
  374. if (key && (item[key] === value[key])) {
  375. return false
  376. } else if (item === value) {
  377. return false
  378. }
  379. }
  380. array.push(value)
  381. return true
  382. }
  383. /**
  384. * 可用于判断是否成功
  385. * @type {symbol}
  386. */
  387. export const succeedSymbol = Symbol()
  388. /**
  389. * 可用于判断是否失败
  390. * @type {symbol}
  391. */
  392. export const failedSymbol = Symbol()
  393. /**
  394. * 使 promise 无论如何都会 resolve,除非传入的参数不是一个Promise对象或返回Promise对象的方法
  395. * 一般用在 Promise.all 中
  396. *
  397. * @param promise 可传Promise对象或返回Promise对象的方法
  398. * @returns {Promise<any>}
  399. */
  400. export function alwaysResolve(promise) {
  401. return new Promise((resolve, reject) => {
  402. let p = promise
  403. if (typeof promise === 'function') {
  404. p = promise()
  405. }
  406. if (p instanceof Promise) {
  407. p.then(data => {
  408. resolve({ type: succeedSymbol, data })
  409. }).catch(error => {
  410. resolve({ type: failedSymbol, error })
  411. })
  412. } else {
  413. reject('alwaysResolve: 传入的参数不是一个Promise对象或返回Promise对象的方法')
  414. }
  415. })
  416. }
  417. /**
  418. * 简单实现防抖方法
  419. *
  420. * 防抖(debounce)函数在第一次触发给定的函数时,不立即执行函数,而是给出一个期限值(delay),比如100ms。
  421. * 如果100ms内再次执行函数,就重新开始计时,直到计时结束后再真正执行函数。
  422. * 这样做的好处是如果短时间内大量触发同一事件,只会执行一次函数。
  423. *
  424. * @param fn 要防抖的函数
  425. * @param delay 防抖的毫秒数
  426. * @returns {Function}
  427. */
  428. export function simpleDebounce(fn, delay = 100) {
  429. let timer = null
  430. return function () {
  431. let args = arguments
  432. if (timer) {
  433. clearTimeout(timer)
  434. }
  435. timer = setTimeout(() => {
  436. fn.apply(this, args)
  437. }, delay)
  438. }
  439. }
  440. /**
  441. * 不用正则的方式替换所有值
  442. * @param text 被替换的字符串
  443. * @param checker 替换前的内容
  444. * @param replacer 替换后的内容
  445. * @returns {String} 替换后的字符串
  446. */
  447. export function replaceAll(text, checker, replacer) {
  448. let lastText = text
  449. text = text.replace(checker, replacer)
  450. if (lastText !== text) {
  451. return replaceAll(text, checker, replacer)
  452. }
  453. return text
  454. }
  455. /**
  456. * 获取事件冒泡路径,兼容 IE11,Edge,Chrome,Firefox,Safari
  457. * 目前使用的地方:JEditableTable Span模式
  458. */
  459. export function getEventPath(event) {
  460. let target = event.target
  461. let path = (event.composedPath && event.composedPath()) || event.path
  462. if (path != null) {
  463. return (path.indexOf(window) < 0) ? path.concat(window) : path
  464. }
  465. if (target === window) {
  466. return [window]
  467. }
  468. let getParents = (node, memo) => {
  469. memo = memo || []
  470. const parentNode = node.parentNode
  471. if (!parentNode) {
  472. return memo
  473. } else {
  474. return getParents(parentNode, memo.concat(parentNode))
  475. }
  476. }
  477. return [target].concat(getParents(target), window)
  478. }
  479. /**
  480. * 根据组件名获取父级
  481. * @param vm
  482. * @param name
  483. * @returns {Vue | null|null|Vue}
  484. */
  485. export function getVmParentByName(vm, name) {
  486. let parent = vm.$parent
  487. if (parent && parent.$options) {
  488. if (parent.$options.name === name) {
  489. return parent
  490. } else {
  491. let res = getVmParentByName(parent, name)
  492. if (res) {
  493. return res
  494. }
  495. }
  496. }
  497. return null
  498. }
  499. /**
  500. * 根据配置返回默认值
  501. * @param vm
  502. * @param name
  503. * @returns {Vue | null|null|Vue}
  504. */
  505. export function getDefValue(value) {
  506. if (value === '${currentYear}') {
  507. return new Date().getFullYear()
  508. } else if (value === '${currentDate}') {
  509. let currentDate = new Date()
  510. currentDate = currentDate.getFullYear() + '-' + currentDate.getMonth() + 1 + '-' + currentDate.getDate()
  511. return currentDate
  512. } else {
  513. return value
  514. }
  515. }
  516. /**
  517. * 使一个值永远不会为(null | undefined)
  518. *
  519. * @param value 要处理的值
  520. * @param def 默认值,如果value为(null | undefined)则返回的默认值,可不传,默认为''
  521. */
  522. export function neverNull(value, def) {
  523. return value == null ? (neverNull(def, '')) : value
  524. }
  525. /**
  526. * 根据元素值移除数组中的一个元素
  527. * @param array 数组
  528. * @param prod 属性名
  529. * @param value 属性值
  530. * @returns {string}
  531. */
  532. export function removeArrayElement(array, prod, value) {
  533. let index = -1
  534. for(let i = 0;i<array.length;i++){
  535. if(array[i][prod] == value){
  536. index = i;
  537. break;
  538. }
  539. }
  540. if(index>=0){
  541. array.splice(index, 1);
  542. }
  543. }
  544. /** 判断是否是OAuth2APP环境 */
  545. export function isOAuth2AppEnv() {
  546. return /wxwork|dingtalk/i.test(navigator.userAgent)
  547. }
  548. /**
  549. * 获取积木报表打印地址
  550. * @param url
  551. * @param id
  552. * @param open 是否自动打开
  553. * @returns {*}
  554. */
  555. export function getReportPrintUrl(url, id, open) {
  556. // URL支持{{ window.xxx }}占位符变量
  557. url = url.replace(/{{([^}]+)?}}/g, (s1, s2) => eval(s2))
  558. if (url.includes('?')) {
  559. url += '&'
  560. } else {
  561. url += '?'
  562. }
  563. url += `id=${id}`
  564. url += `&token=${Vue.ls.get(ACCESS_TOKEN)}`
  565. if (open) {
  566. window.open(url)
  567. }
  568. return url
  569. }