yunqi.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. const __=function (key,data) {
  2. if(!key || typeof key!='string'){
  3. return '';
  4. }
  5. let r=key.toLowerCase();
  6. r=Yunqi.config.locale[r] || key;
  7. for(let i in data){
  8. r=r.replace('%'+i,data[i])
  9. }
  10. return r;
  11. };
  12. window.Yunqi=(function(){
  13. let elloading;
  14. let rand=function(n,m){
  15. return Math.floor(Math.random() * (m - n + 1)) + n;
  16. }
  17. let showLoading=function () {
  18. elloading=Yunqi.loading({text:'请求中..'});
  19. }
  20. let request=function(type, url, obj, loading,showmsg,all=false){
  21. if(!url){
  22. throw new Error('url不能为空');
  23. return;
  24. }
  25. if(!url.startsWith('http') && !url.startsWith('/')){
  26. url=Yunqi.config.baseUrl+url;
  27. }
  28. let headers={
  29. 'content-type':'application/x-www-form-urlencoded; charset=UTF-8',
  30. 'x-requested-with':'XMLHttpRequest'
  31. }
  32. let pro = new Promise((resolve, reject) => {
  33. if(type=='get'){
  34. if(obj){
  35. let str='';
  36. for(var i in obj){
  37. if(obj[i] instanceof Array){
  38. obj[i]=obj[i].join(',');
  39. }
  40. str+='&'+i+'='+obj[i];
  41. }
  42. if(url.indexOf('?')==-1){
  43. url=url+'?'+str.slice(1);
  44. }else{
  45. url+=str;
  46. }
  47. }
  48. }
  49. if(type=='json'){
  50. headers['content-type']='application/json';
  51. }
  52. if(loading){
  53. showLoading();
  54. }
  55. axios({
  56. url: url,
  57. data: obj,
  58. method: type,
  59. headers:headers
  60. }).then(response=>{
  61. if (loading) {
  62. elloading.close();
  63. }
  64. if (response.status == 200) {
  65. let res=response.data;
  66. //表格数据
  67. if(res.rows && res.total!==undefined){
  68. resolve(res);
  69. }else if (res.code === 1) {
  70. let msg=res.msg || __('操作完成')
  71. if (showmsg) {
  72. Yunqi.message.success(msg);
  73. }
  74. resolve(res.data);
  75. }else if (res.code === 0) {
  76. let msg=res.msg || '';
  77. if (msg) {
  78. Yunqi.message.error(msg);
  79. }
  80. reject(res);
  81. }else if(all){
  82. resolve(res);
  83. }else{
  84. Yunqi.message.error('未知数据');
  85. }
  86. }
  87. }).catch(err=>{
  88. if (loading) {
  89. elloading.close();
  90. }
  91. Yunqi.message.error(err.response.data);
  92. reject();
  93. });
  94. });
  95. return pro;
  96. }
  97. function SupposeClass(){
  98. //系统配置
  99. this.config='';
  100. //系统变量
  101. this.data='';
  102. //系统权限
  103. this.auth='';
  104. //page应用
  105. this.app='';
  106. this.formatter={
  107. text:{
  108. _name:'text'
  109. },
  110. html:{
  111. _name:'html'
  112. },
  113. image:{
  114. _name:'image',
  115. },
  116. images:{
  117. _name:'images',
  118. },
  119. link:{
  120. _name:'link'
  121. },
  122. datetime:{
  123. _name:'datetime'
  124. },
  125. date:{
  126. _name:'date'
  127. },
  128. tag:{
  129. _name:'tag',
  130. effect:'dark'
  131. },
  132. tags:{
  133. _name:'tags',
  134. effect:'dark'
  135. },
  136. button:{
  137. _name:'button',
  138. title:'按钮',
  139. type:'primary',
  140. click:function (){}
  141. },
  142. switch:{
  143. _name:'switch',
  144. inactiveValue:0,
  145. activeValue:1,
  146. disabled:false
  147. },
  148. select:{
  149. _name:'select',
  150. disabled:false
  151. },
  152. slot:{
  153. _name:'slot'
  154. }
  155. };
  156. this.api={
  157. //打开选项卡
  158. addtabs:function(options){
  159. let config=top.Yunqi.config;
  160. if(config.controller!='app\\admin\\controller\\Index' && config.action!='index'){
  161. Yunqi.message.error(__('请在框架内执行该操作'));
  162. return;
  163. }
  164. if(!options.url){
  165. Yunqi.message.error(__('url不能为空'));
  166. return;
  167. }
  168. if(!options.url.startsWith('http')){
  169. //绝对路径
  170. if(options.url.startsWith('/')){
  171. options.url=document.origin+options.url;
  172. //相对路径
  173. }else{
  174. options.url=Yunqi.config.baseUrl+options.url;
  175. }
  176. }
  177. let menu={
  178. url:options.url,
  179. icon:options.icon,
  180. title:options.title,
  181. menutype:'tab',
  182. close:options.close || function (){}
  183. };
  184. top.Yunqi.app.clickMenu(menu);
  185. },
  186. open:function (options) {
  187. let config=top.Yunqi.config;
  188. if(config.controller!='app\\admin\\controller\\Index' && config.action!='index'){
  189. Yunqi.message.error(__('请在框架内执行该操作'));
  190. return;
  191. }
  192. if(!options.url){
  193. Yunqi.message.error(__('url不能为空'));
  194. return;
  195. }
  196. if(!options.url.startsWith('http')){
  197. //绝对路径
  198. if(options.url.startsWith('/')){
  199. options.url=document.origin+options.url;
  200. //相对路径
  201. }else{
  202. options.url=Yunqi.config.baseUrl+options.url;
  203. }
  204. }
  205. let menu={
  206. url:options.url,
  207. expand:options.expand || false,
  208. icon:options.icon,
  209. title:options.title,
  210. width:options.width || 800,
  211. height:options.height || 500,
  212. close:options.close || function (e){},
  213. menutype:'layer'
  214. };
  215. top.Yunqi.app.clickMenu(menu);
  216. },
  217. //关闭选项卡
  218. closetabs:function(options,data){
  219. let config=top.Yunqi.config;
  220. if(config.controller!='app\\admin\\controller\\Index' && config.action!='index'){
  221. Yunqi.message.error(__('请在框架内执行该操作'));
  222. return;
  223. }
  224. top.Yunqi.app.clickMenu(top.Yunqi.app.tabList[0]);
  225. top.Yunqi.app.closeTabs(options,data);
  226. },
  227. closelayer:function (options,data) {
  228. let config=top.Yunqi.config;
  229. if(config.controller!='app\\admin\\controller\\Index' && config.action!='index'){
  230. Yunqi.message.error(__('请在框架内执行该操作'));
  231. return;
  232. }
  233. top.Yunqi.app.closeLayer(options,data);
  234. },
  235. //预览图片
  236. previewImg:function (img){
  237. let config=top.Yunqi.config;
  238. if(config.controller!='app\\admin\\controller\\Index' && config.action!='index'){
  239. if(img instanceof Array){
  240. Yunqi.message.error(__('请在框架内执行该操作'));
  241. }else{
  242. window.open(img,'_blank');
  243. }
  244. return;
  245. }
  246. top.Yunqi.app.previewImg(img);
  247. },
  248. //窗口最大化
  249. expand:function () {
  250. let config=top.Yunqi.config;
  251. if(config.controller!='app\\admin\\controller\\Index' && config.action!='index'){
  252. return;
  253. }
  254. top.Yunqi.app.expand();
  255. },
  256. //窗口缩小
  257. compress:function () {
  258. let config=top.Yunqi.config;
  259. if(config.controller!='app\\admin\\controller\\Index' && config.action!='index'){
  260. return;
  261. }
  262. top.Yunqi.app.compress();
  263. },
  264. del:function(url,ids,callback) {
  265. let nodata=false;
  266. if(!ids){
  267. nodata=true;
  268. }
  269. if(ids instanceof Array && ids.length===0){
  270. nodata=true;
  271. }
  272. if(typeof ids=='string' || typeof ids=='number'){
  273. ids=[ids]
  274. }
  275. if(nodata){
  276. Yunqi.alert(__('没有要删除的数据'),__('温馨提示'),{type: 'error'});
  277. return;
  278. }
  279. Yunqi.confirm(__('确定删除选中的 %s 项?',{'s':ids.length}),__('温馨提示'),{type: 'warning'}).then(res=>{
  280. Yunqi.ajax.post(url,{ids:ids.join(',')}).then(data=>{
  281. callback && callback();
  282. });
  283. });
  284. },
  285. multi:function(url,options,callback='',error=''){
  286. let nodata=false;
  287. if(!options.ids){
  288. nodata=true;
  289. }
  290. if(options.ids instanceof Array && options.ids.length===0){
  291. nodata=true;
  292. }
  293. if(typeof options.ids=='string' || typeof options.ids=='number'){
  294. options.ids=[options.ids];
  295. }
  296. if(nodata){
  297. Yunqi.alert('没有要更新的数据!','温馨提示',{type: 'warning'});
  298. return;
  299. }
  300. Yunqi.ajax.post(url,options).then(data=>{
  301. callback && callback();
  302. }).catch(e=>{
  303. error && error(e);
  304. });
  305. }
  306. };
  307. this.ajax={
  308. get:function(url,data,loading=false,showmsg=false,fulldata=false) {
  309. return request('get',url,data,loading,showmsg,fulldata);
  310. },
  311. post:function(url,data,loading=true,showmsg=true,fulldata=false){
  312. return request('post',url,data,loading,showmsg,fulldata);
  313. },
  314. json:function(url,data,loading=false,showmsg=false,fulldata=false){
  315. return request('json',url,data,loading,showmsg,fulldata);
  316. }
  317. };
  318. this.getApp=function (id){
  319. let doc=top.document.querySelector('iframe[id="addtabs-'+id+'"]') || top.document.querySelector('iframe[id="layer-'+id+'"]');
  320. return doc && doc.contentWindow && doc.contentWindow.Yunqi && doc.contentWindow.Yunqi.app;
  321. },
  322. this.getElementUi=function (key=''){
  323. let ui=this.config.elementUi;
  324. for(let k in ui){
  325. if(ui[k]==='true'){
  326. ui[k]=true;
  327. }
  328. if(ui[k]==='false'){
  329. ui[k]=false;
  330. }
  331. }
  332. if(key){
  333. return ui[key];
  334. }
  335. return ui;
  336. };
  337. this.use=function (arr){
  338. const oldkeys=Object.keys(window);
  339. if(typeof arr=='string'){
  340. arr=[arr];
  341. }
  342. const promises = arr.map(fileurl => {
  343. return new Promise((resolve, reject) => {
  344. let script=document.createElement("script");
  345. script.src=fileurl;
  346. script.type='text/javascript';
  347. script.onload = resolve;
  348. script.onerror = reject;
  349. document.querySelector('head').appendChild(script);
  350. });
  351. });
  352. return new Promise((resolve, reject) => {
  353. Promise.all(promises).then(res=>{
  354. let newKeys=Object.keys(window);
  355. let keys=newKeys.filter(v=>!oldkeys.includes(v));
  356. let obj;
  357. if(keys.length==1){
  358. obj=window[keys[0]];
  359. }else{
  360. obj={};
  361. for(let i=0;i<keys.length;i++) {
  362. obj[keys[i]]=window[keys[i]];
  363. }
  364. }
  365. resolve(obj);
  366. });
  367. });
  368. };
  369. this.setThemeColor=function(){
  370. const hexToRgb=function (str) {
  371. let hexs = "";
  372. str = str.replace("#", "");
  373. hexs = str.match(/../g);
  374. for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16);
  375. return hexs;
  376. }
  377. const rgbToHex=function (r, g, b) {
  378. let hexs = [r.toString(16), g.toString(16), b.toString(16)];
  379. for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`;
  380. return `#${hexs.join("")}`;
  381. }
  382. const getDarkColor=function(color, level) {
  383. let rgb = hexToRgb(color);
  384. for (let i = 0; i < 3; i++) rgb[i] = Math.round(20.5 * level + rgb[i] * (1 - level));
  385. return rgbToHex(rgb[0], rgb[1], rgb[2]);
  386. }
  387. const getLightColor=function (color, level) {
  388. let rgb = hexToRgb(color);
  389. for (let i = 0; i < 3; i++) rgb[i] = Math.round(255 * level + rgb[i] * (1 - level));
  390. return rgbToHex(rgb[0], rgb[1], rgb[2]);
  391. }
  392. let elementUi=Yunqi.getElementUi();
  393. // 计算主题颜色变化
  394. document.documentElement.style.setProperty("--el-color-primary", elementUi.theme_color);
  395. document.documentElement.style.setProperty(
  396. "--el-color-primary-dark-2",
  397. elementUi.is_dark ? `${getLightColor(elementUi.theme_color, 0.2)}` : `${getDarkColor(elementUi.theme_color, 0.3)}`
  398. );
  399. for (let i = 1; i <= 9; i++) {
  400. const primaryColor = elementUi.is_dark ? `${getDarkColor(elementUi.theme_color, i / 10)}` : `${getLightColor(elementUi.theme_color, i / 10)}`;
  401. document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, primaryColor);
  402. }
  403. };
  404. };
  405. SupposeClass.prototype = {
  406. constructor: SupposeClass,
  407. setUp:function (Pageinfo,zhCn){
  408. function resolvePromiseInObject(obj) {
  409. const promises = [];
  410. for(let key in obj){
  411. if(typeof key!='string'){
  412. continue;
  413. }
  414. const value = obj[key];
  415. if (value instanceof Promise) {
  416. promises.push(
  417. value.then(res => {
  418. if(typeof res === 'object'){
  419. promises.push(resolvePromiseInObject(res));
  420. }
  421. obj[key] =res;
  422. })
  423. );
  424. } else if (typeof value === 'object') {
  425. promises.push(resolvePromiseInObject(value));
  426. }
  427. }
  428. return Promise.all(promises).then(() => {
  429. return obj;
  430. });
  431. }
  432. function recyclebin_(type,val){
  433. if(typeof type=='object'){
  434. val=[type];
  435. type='restore';
  436. }
  437. if(type=='init'){
  438. let columns=[];
  439. columns.push({checkbox: true});
  440. for(let key in Yunqi.data.columns){
  441. let type=Yunqi.data.columnsType[key] || 'text';
  442. let formatter=Yunqi.formatter[type];
  443. columns.push({
  444. field: key,
  445. title: Yunqi.data.columns[key],
  446. formatter: formatter
  447. });
  448. }
  449. columns.push({
  450. field: 'deletetime',
  451. title: __('删除时间'),
  452. formatter: Yunqi.formatter.datetime
  453. });
  454. columns.push({
  455. field: 'operate',
  456. fixed:'right',
  457. title: __('操作'),
  458. width:80,
  459. action:{
  460. restore:{
  461. tooltip:true,
  462. type:'success',
  463. text:__('还原'),
  464. icon:'fa fa-undo',
  465. method:'recyclebin_'
  466. }
  467. }
  468. });
  469. return columns;
  470. }
  471. if(type=='restore' || type=='destroy'){
  472. let ids=[];
  473. val.forEach(res=>{
  474. ids.push(res.id);
  475. });
  476. if(ids.length==0){
  477. this.$message.error(__('请选择需要操作的数据'));
  478. return false;
  479. }
  480. Yunqi.ajax.post(this.extend.recyclebin_url+'?action='+type,{ids:ids}).then(res=>{
  481. this.$refs.yuntable.reset();
  482. });
  483. }
  484. if(type=='restoreall' || type=='clear'){
  485. let msg={
  486. restoreall:__('确定还原全部数据吗?'),
  487. clear:__('确定清空回收站吗?')
  488. };
  489. Yunqi.confirm(msg[type],__('温馨提示'),{type: 'warning'}).then(res=>{
  490. Yunqi.ajax.post(this.extend.recyclebin_url+'?action='+type).then(res=>{
  491. this.$refs.yuntable.reset();
  492. });
  493. });
  494. }
  495. }
  496. function setContentHeight_(){
  497. let el=document.querySelector('#mainScrollbar>.el-scrollbar>.el-scrollbar__wrap');
  498. if(!el){
  499. return;
  500. }
  501. //全屏
  502. if(top!=window && top.Yunqi.app.mainFrameExpand){
  503. Vue.nextTick(()=>{
  504. el.style.height=document.documentElement.clientHeight+'px';
  505. });
  506. }
  507. //非全屏
  508. if(top!=window && !top.Yunqi.app.mainFrameExpand){
  509. //弹出窗
  510. let iframe=top.document.querySelector('iframe[src="'+decodeURI(window.location.href)+'"][class="layer-iframe"]');
  511. if(iframe){
  512. Vue.nextTick(()=>{
  513. el.style.height=iframe.height+'px';
  514. });
  515. //正常窗
  516. }else{
  517. Vue.nextTick(()=>{
  518. el.style.height=top.Yunqi.app.contentHeight+'px';
  519. });
  520. }
  521. }
  522. }
  523. resolvePromiseInObject(Pageinfo).then(Pageinfo=>{
  524. let Counter={
  525. updated:Pageinfo.updated || function(){},
  526. computed:Pageinfo.computed || {},
  527. watch:Pageinfo.watch || {},
  528. components:Pageinfo.components || {}
  529. };
  530. if(Pageinfo.data && typeof Pageinfo.data=='function'){
  531. Counter.data=Pageinfo.data;
  532. }
  533. if(Pageinfo.data && typeof Pageinfo.data=='object'){
  534. Counter.data=function(){
  535. return Pageinfo.data;
  536. }
  537. }
  538. let onLoad=function(){};
  539. let onUnload=function(){};
  540. let onShow=function(){};
  541. let onHide=function(){};
  542. if(Pageinfo.onLoad!=undefined && typeof Pageinfo.onLoad=='function'){
  543. onLoad=Pageinfo.onLoad;
  544. }
  545. if(Pageinfo.onUnload!=undefined && typeof Pageinfo.onUnload=='function'){
  546. onUnload=Pageinfo.onUnload;
  547. }
  548. if(Pageinfo.onShow!=undefined && typeof Pageinfo.onShow=='function'){
  549. onShow=Pageinfo.onShow;
  550. }
  551. if(Pageinfo.onHide!=undefined && typeof Pageinfo.onHide=='function'){
  552. onHide=Pageinfo.onHide;
  553. }
  554. Counter.methods={...Pageinfo.methods,recyclebin_,setContentHeight_,onLoad,onUnload,onShow,onHide};
  555. let created=Pageinfo.created || function(){};
  556. Counter.created=function(){
  557. Yunqi.setThemeColor();
  558. Yunqi.setApp(this);
  559. this.onLoad(Yunqi.config.query);
  560. created();
  561. }
  562. let mounted=Pageinfo.mounted || function(){};
  563. Counter.mounted=function(){
  564. document.getElementById('container').style.display='flex';
  565. let dark=Yunqi.getElementUi()['dark'];
  566. if(dark){
  567. document.querySelector('html').classList.add('dark');
  568. }else{
  569. document.querySelector('html').classList.remove('dark');
  570. }
  571. this.onShow();
  572. this.setContentHeight_();
  573. mounted();
  574. }
  575. let jsFile=Yunqi.config.baseUrl+'../assets/js/';
  576. //先加载vue
  577. this.use(jsFile+'vue.global.js').then(res=>{
  578. let {Vue}=res;
  579. //再加载axios、element-plus等
  580. this.use([
  581. jsFile+'axios.min.js',
  582. jsFile+'Sortable.min.js',
  583. jsFile+'element-plus.js'
  584. ]).then(xes=>{
  585. let {ElementPlus}=xes;
  586. //追加到Yunqi对象
  587. this.message=top.ElementPlus.ElMessage;
  588. this.confirm=top.ElementPlus.ElMessageBox.confirm;
  589. this.prompt=top.ElementPlus.ElMessageBox.prompt;
  590. this.alert=top.ElementPlus.ElMessageBox.alert;
  591. this.loading=top.ElementPlus.ElLoading.service;
  592. let app=Vue.createApp(Counter);
  593. app.use(ElementPlus, {locale: zhCn});
  594. for(let k in Counter.components){
  595. let rs=Counter.components[k];
  596. app.component(k,rs);
  597. }
  598. app.mount('#app');
  599. });
  600. });
  601. });
  602. },
  603. setConfig: function(arg,value){
  604. if(!this.config){
  605. this.config=arg;
  606. }else{
  607. this.config[arg]=value;
  608. }
  609. return this;
  610. },
  611. setAuth:function(arg,value){
  612. if(!this.auth){
  613. let _this=this;
  614. this.auth=arg;
  615. //权限判断
  616. this.auth.check=function(controller,action){
  617. if(_this.auth.rules_list=='*'){
  618. return true;
  619. }
  620. for (let i in _this.auth.rules_list){
  621. let rule=_this.auth.rules_list[i];
  622. if(rule.controller==controller){
  623. for(let j in rule.action){
  624. let v=rule.action[j];
  625. if(v==action){
  626. return true;
  627. }
  628. }
  629. }
  630. }
  631. return false;
  632. }
  633. }else{
  634. this.auth[arg]=value;
  635. }
  636. return this;
  637. },
  638. setData:function (data,value){
  639. if(!this.data){
  640. this.data=data;
  641. }else{
  642. this.data[data]=value;
  643. }
  644. return this;
  645. },
  646. setApp: function(app){
  647. if(app.window){
  648. throw new Error('页面禁止使用window属性');
  649. }
  650. app.window={
  651. menutype:'blank',
  652. };
  653. if(top!==window){
  654. let menu=top.Yunqi.app.openMenu;
  655. app.window.id=menu.id;
  656. app.window.title=menu.title;
  657. app.window.url=menu.url;
  658. app.window.menutype=menu.menutype;
  659. }
  660. this.app=app;
  661. return this;
  662. }
  663. };
  664. return new SupposeClass();
  665. })();