fileChoose.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /**
  2. * 文件选择扩展模块
  3. * date:2019-07-12 License By http://easyweb.vip
  4. */
  5. layui.define(['jquery', 'layer', 'form', 'upload', 'util'], function (exports) {
  6. var $ = layui.jquery;
  7. var layer = layui.layer;
  8. var form = layui.form;
  9. var upload = layui.upload;
  10. var util = layui.util;
  11. /** 文件后缀对应图标 */
  12. var fileIcons = [{
  13. suffix: ['ppt', 'pptx'],
  14. icon: 'ppt'
  15. }, {
  16. suffix: ['doc', 'docx'],
  17. icon: 'doc'
  18. }, {
  19. suffix: ['xls', 'xlsx'],
  20. icon: 'xls'
  21. }, {
  22. suffix: ['pdf'],
  23. icon: 'pdf'
  24. }, {
  25. suffix: ['html', 'htm'],
  26. icon: 'htm'
  27. }, {
  28. suffix: ['txt'],
  29. icon: 'txt'
  30. }, {
  31. suffix: ['swf', 'docx'],
  32. icon: 'flash'
  33. }, {
  34. suffix: ['zip', 'rar', '7z'],
  35. icon: 'zip'
  36. }, {
  37. suffix: ['mp3', 'wav'],
  38. icon: 'mp3'
  39. }, {
  40. suffix: ['mp4', '3gp', 'rmvb', 'avi', 'flv'],
  41. icon: 'mp4'
  42. }, {
  43. suffix: ['psd'],
  44. icon: 'psd'
  45. }, {
  46. suffix: ['ttf'],
  47. icon: 'ttf'
  48. }, {
  49. suffix: ['apk'],
  50. icon: 'apk'
  51. }, {
  52. suffix: ['exe'],
  53. icon: 'exe'
  54. }, {
  55. suffix: ['torrent'],
  56. icon: 'bt'
  57. }, {
  58. suffix: ['gif', 'png', 'jpeg', 'jpg', 'bmp'],
  59. icon: 'img'
  60. }];
  61. var fileChoose = {};
  62. /** 打开选择文件弹窗 */
  63. fileChoose.open = function (param) {
  64. var fileUrl = param.fileUrl; // 文件查看url
  65. var listUrl = param.listUrl; // 文件列表url
  66. var where = param.where; // 文件列表请求参数
  67. var chooseNum = param.num; // 文件选择的数量
  68. var onChoose = param.onChoose; // 选择回调
  69. var uploadOption = param.upload; // 文件上传配置
  70. var dialogOption = param.dialog; // 弹窗配置
  71. var operMenu = param.menu; // 操作菜单
  72. var operMenuClick = param.menuClick; // 操作菜单事件处理
  73. var response = param.response ? param.response : {}; // 返回数据格式
  74. var dirName = response.dir; // 文件列表请求参数文件夹名称
  75. var okCode = response.code; // 成功码
  76. var urlName = response.url; // url名称
  77. var smUrlName = response.smUrl; // 缩略图名称
  78. var isDirName = response.isDir; // 是否是文件夹名称
  79. var titleName = response.name; // 文件名称字段名
  80. var method = response.method; // 文件名称字段名
  81. var parseData = response.parseData; // 数据格式化
  82. var dataList = []; // 当前文件列表
  83. // 设置默认参数
  84. where || (where = {});
  85. (chooseNum != undefined) || (chooseNum = 1);
  86. uploadOption || (uploadOption = {});
  87. dialogOption || (dialogOption = {});
  88. dirName || (dirName = 'dir');
  89. (okCode != undefined) || (okCode = 200);
  90. urlName || (urlName = 'url');
  91. smUrlName || (smUrlName = 'smUrl');
  92. isDirName || (isDirName = 'isDir');
  93. titleName || (titleName = 'name');
  94. method || (method = 'get');
  95. // 显示弹窗
  96. dialogOption.id = 'file-choose-dialog';
  97. dialogOption.type = 1;
  98. (dialogOption.title != undefined) || (dialogOption.title = '选择文件');
  99. dialogOption.content = '';
  100. dialogOption.area || (dialogOption.area = ['565px', '420px']);
  101. (dialogOption.shade != undefined) || (dialogOption.shade = .1);
  102. dialogOption.fixed || (dialogOption.fixed = false);
  103. dialogOption.skin || (dialogOption.skin = 'layer-file-choose');
  104. var sCallBack = param.success;
  105. dialogOption.success = function (layero, dIndex) {
  106. $(layero).children('.layui-layer-content').load(layui.cache.base + 'fileChoose/fileChoose.html', function () {
  107. init(); // 渲染页面
  108. sCallBack && sCallBack(layero, index);
  109. });
  110. };
  111. layer.open(dialogOption);
  112. // 获取文件列表
  113. function loadList(dir) {
  114. dir || (dir = $('#fc-current-position').text());
  115. $('.file-choose-dialog .file-choose-loading-group').removeClass('layui-hide');
  116. where[dirName] = dir;
  117. $('#file-choose-list').html('');
  118. $.ajax({
  119. url: listUrl,
  120. type: method,
  121. data: where,
  122. dataType: 'json',
  123. success: function (res) {
  124. parseData && (res = parseData(res));
  125. if (res.code == okCode) {
  126. dataList = res.data;
  127. $('#fc-btn-ok-sel').text('完成选择');
  128. $('#file-choose-list').html(fileChoose.renderList({
  129. fileUrl: fileUrl,
  130. data: dataList,
  131. multi: chooseNum > 1,
  132. menu: operMenu,
  133. response: response
  134. }));
  135. form.render('checkbox');
  136. } else {
  137. layer.msg(res.msg, {icon: 2, anim: 6});
  138. $('#file-choose-list').html(fileChoose.getErrorHtml('加载失败', 'layui-icon-face-cry'));
  139. }
  140. setTimeout(function () {
  141. $('.file-choose-dialog .file-choose-loading-group').addClass('layui-hide');
  142. }, 200);
  143. }
  144. });
  145. }
  146. // 事件处理
  147. function init() {
  148. (chooseNum > 1) || ($('.file-choose-dialog').addClass('hide-bottom'));
  149. loadList();
  150. // 刷新
  151. $('#fc-btn-refresh').click(function () {
  152. loadList();
  153. });
  154. // 返回上级
  155. $('#fc-btn-back').click(function () {
  156. var cDir = $('#fc-current-position').text();
  157. if (cDir != '/') {
  158. cDir = cDir.substring(0, cDir.lastIndexOf('/'));
  159. cDir || (cDir = '/');
  160. $('#fc-current-position').text(cDir);
  161. loadList(cDir);
  162. }
  163. });
  164. // 上传文件事件
  165. uploadOption.elem = '#fc-btn-upload';
  166. uploadOption.data || (uploadOption.data = {});
  167. uploadOption.data.dir = function () {
  168. return $('#fc-current-position').text();
  169. };
  170. uploadOption.before = function () {
  171. layer.load(2);
  172. };
  173. uploadOption.done = function (res, index, upload) {
  174. layer.closeAll('loading');
  175. if (res.code != okCode) {
  176. layer.msg(res.msg, {icon: 2});
  177. } else {
  178. layer.msg(res.msg, {icon: 1});
  179. var dir = res.dir ? res.dir : util.toDateString(new Date(), '/yyyy/MM/dd');
  180. $('#fc-current-position').text(dir);
  181. loadList();
  182. }
  183. };
  184. uploadOption.error = function () {
  185. layer.closeAll('loading');
  186. layer.msg('上传失败', {icon: 2});
  187. };
  188. upload.render(uploadOption);
  189. // 完成选择按钮
  190. $('#fc-btn-ok-sel').click(function () {
  191. var urls = [];
  192. $('input[lay-filter="file-choose-item-ck"]:checked').each(function () {
  193. var dataIndex = $(this).parents('.file-choose-list-item').data('index');
  194. urls.push(dataList[dataIndex]);
  195. });
  196. if (urls.length <= 0) {
  197. layer.msg('请选择', {icon: 2, anim: 6});
  198. } else if (urls.length > chooseNum) {
  199. layer.msg('最多只能选择' + chooseNum + '个', {icon: 2, anim: 6});
  200. } else {
  201. okChoose(urls);
  202. }
  203. });
  204. // 列表点击事件
  205. $(document).off('click.fcli').on('click.fcli', '.file-choose-dialog .file-choose-list-item', function (e) {
  206. var item = dataList[$(this).data('index')];
  207. if (item[isDirName]) { // 是否是文件夹
  208. var cDir = $('#fc-current-position').text();
  209. cDir += (cDir == '/' ? item[titleName] : ('/' + item[titleName]));
  210. $('#fc-current-position').text(cDir);
  211. loadList(cDir);
  212. } else {
  213. var $cMenu = $(this).find('.file-choose-oper-menu');
  214. $('.file-choose-dialog .file-choose-oper-menu').not($cMenu).removeClass('show');
  215. $cMenu.toggleClass('show');
  216. e.stopPropagation();
  217. }
  218. });
  219. // 点击空白隐藏下拉框
  220. $(document).off('click.fclom').on('click.fclom', '.file-choose-dialog', function (e) {
  221. $('.file-choose-dialog .file-choose-oper-menu').removeClass('show');
  222. e.stopPropagation();
  223. });
  224. // 监听复选框选中
  225. form.on('checkbox(file-choose-item-ck)', function (data) {
  226. var ckSize = $('.file-choose-dialog input[lay-filter="file-choose-item-ck"]:checked').length;
  227. if (data.elem.checked) {
  228. if (ckSize > chooseNum) {
  229. layer.msg('最多只能选择' + chooseNum + '个', {icon: 2, anim: 6});
  230. $(data.elem).prop('checked', false);
  231. form.render('checkbox');
  232. return;
  233. }
  234. $(data.elem).parents('.file-choose-list-item').addClass('active');
  235. } else {
  236. $(data.elem).parents('.file-choose-list-item').removeClass('active');
  237. }
  238. $('#fc-btn-ok-sel').text('完成选择' + (ckSize > 0 ? ('(' + ckSize + ')') : ''));
  239. });
  240. // 点击多选框阻止列表事件
  241. $(document).off('click.fclic').on('click.fclic', '.file-choose-dialog .file-choose-list-item-ck', function (e) {
  242. e.stopPropagation();
  243. });
  244. // 菜单事件监听
  245. $(document).off('click.fclomi').on('click.fclomi', '.file-choose-dialog .file-choose-oper-menu-item', function () {
  246. var event = $(this).data('event');
  247. var dataIndex = $(this).parent().parent().data('index');
  248. if ('choose' == event) {
  249. if (chooseNum > 1) {
  250. $(this).parent().parent().find('.layui-form-checkbox').trigger('click');
  251. } else {
  252. okChoose([dataList[dataIndex]]);
  253. }
  254. } else if ('preview' == event) {
  255. var url = (fileUrl + dataList[dataIndex][urlName]);
  256. if ('img' == fileChoose.getFileType(url)) {
  257. var imgUrls = [], start = 0;
  258. for (var i = 0; i < dataList.length; i++) {
  259. var tUrl = fileUrl + dataList[i][urlName];
  260. if ('img' == fileChoose.getFileType(tUrl)) {
  261. imgUrls.push({src: tUrl, alt: dataList[i][titleName]});
  262. }
  263. if (url == tUrl) {
  264. start = imgUrls.length - 1;
  265. }
  266. }
  267. layer.photos({photos: {start: start, data: imgUrls}, shade: .1, closeBtn: true});
  268. } else {
  269. layer.confirm('这不是图片类型,可能需要下载才能预览,确定要打开吗?', {
  270. title: '温馨提示',
  271. area: '260px',
  272. shade: .1
  273. }, function (index) {
  274. layer.close(index);
  275. window.open(url);
  276. });
  277. }
  278. } else {
  279. operMenuClick && operMenuClick(event, dataList[dataIndex]);
  280. }
  281. });
  282. }
  283. // 完成选择
  284. function okChoose(urls) {
  285. onChoose && onChoose(urls);
  286. layer.close($('#fc-btn-ok-sel').parents('.layui-layer').attr('id').substring(11));
  287. }
  288. };
  289. // 渲染文件列表
  290. fileChoose.renderList = function (param) {
  291. var fileUrl = param.fileUrl; // 文件服务器地址
  292. var dataList = param.data; // 数据
  293. var multi = param.multi; // 是否多选
  294. var operMenu = param.menu; // 操作菜单
  295. var response = param.response ? param.response : {}; // 返回数据格式
  296. var urlName = response.url; // url名称
  297. var smUrlName = response.smUrl; // 缩略图名称
  298. var isDirName = response.isDir; // 是否是文件夹名称
  299. var titleName = response.name; // 文件名称字段名
  300. (fileUrl == undefined) && (fileUrl = '');
  301. (dataList == undefined) && (dataList = []);
  302. (multi == undefined) && (multi = false);
  303. urlName || (urlName = 'url');
  304. smUrlName || (smUrlName = 'smUrl');
  305. isDirName || (isDirName = 'isDir');
  306. titleName || (titleName = 'name');
  307. var html = '';
  308. if (dataList.length <= 0) {
  309. html += fileChoose.getErrorHtml('没有文件');
  310. } else {
  311. for (var i = 0; i < dataList.length; i++) {
  312. var item = dataList[i];
  313. html += '<div class="file-choose-list-item" data-index="' + i + '">';
  314. var imgUrl = fileUrl + item[smUrlName], fileImgIcon = '';
  315. if (!item[smUrlName]) {
  316. fileImgIcon = ' img-icon';
  317. imgUrl = fileChoose.getFileIcon(item[urlName], item[isDirName]);
  318. }
  319. var bgStyle = "background-image: url('" + imgUrl + "')";
  320. html += ' <div class="file-choose-list-item-img' + fileImgIcon + '" style="' + bgStyle + '"></div>';
  321. html += ' <div class="file-choose-list-item-name" title="' + item[titleName] + '">' + item[titleName] + '</div>';
  322. if (!item[isDirName] && multi) {
  323. html += ' <div class="file-choose-list-item-ck layui-form">';
  324. html += ' <input type="checkbox" lay-skin="primary" lay-filter="file-choose-item-ck"/>';
  325. html += ' </div>';
  326. }
  327. if (!operMenu) {
  328. html += '<div class="file-choose-oper-menu">';
  329. html += ' <div class="file-choose-oper-menu-item" data-event="choose">选择</div>';
  330. html += ' <div class="file-choose-oper-menu-item" data-event="preview">预览</div>';
  331. html += '</div>';
  332. } else if (operMenu.length > 0) {
  333. html += '<div class="file-choose-oper-menu">';
  334. for (var mi = 0; mi < operMenu.length; mi++) {
  335. var menuItem = operMenu[mi];
  336. html += '<div class="file-choose-oper-menu-item" data-event="' + menuItem.event + '">' + menuItem.name + '</div>';
  337. }
  338. html += '</div>';
  339. }
  340. html += '</div>';
  341. }
  342. }
  343. return html;
  344. };
  345. // 显示空布局或错误布局
  346. fileChoose.getErrorHtml = function (msg, icon) {
  347. icon || (icon = 'layui-icon-face-surprised');
  348. var html = '';
  349. html += '<div class="file-choose-empty">';
  350. html += ' <i class="layui-icon ' + icon + '"></i>';
  351. html += ' <p>' + msg + '</p>';
  352. html += '</div>';
  353. return html;
  354. };
  355. // 根据文件后缀获取图标
  356. fileChoose.getFileIcon = function (url, isDir) {
  357. var type = isDir ? 'dir' : fileChoose.getFileType(url);
  358. return layui.cache.base + 'fileChoose/img/' + type + '.png';
  359. };
  360. // 根据文件后缀获取文件类型
  361. fileChoose.getFileType = function (url) {
  362. var type = 'file';
  363. var suffix = url.substring(url.lastIndexOf('.') + 1);
  364. for (var i = 0; i < fileIcons.length; i++) {
  365. for (var j = 0; j < fileIcons[i].suffix.length; j++) {
  366. if (suffix.toLowerCase() == fileIcons[i].suffix[j]) {
  367. type = fileIcons[i].icon;
  368. break;
  369. }
  370. }
  371. }
  372. return type;
  373. };
  374. $('body').append('<style>.layer-file-choose { max-width: 100%;}</style>');
  375. exports("fileChoose", fileChoose);
  376. });