imageTable.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <template>
  2. <div class="w-8/12 h-5/6 p-2 rounded flex flex-col justify-center border bg-white">
  3. <div class="p-header mx-1.5 h-16 text-2xl flex border-b">
  4. <!-- 刷新按钮-->
  5. <a-button class="ant-icon-btn" type="primary" icon="reload" :loading="loadingState === 0" @click="loadImage" ></a-button>
  6. <a-button class="ml-2" :type="tabKey===1?'primary':''" @click="callback(1)">选择图片</a-button>
  7. <a-button class="ml-1" :type="tabKey===2?'primary':''" @click="callback(2)">上传图片</a-button>
  8. </div>
  9. <div class="p-con w-full px-1">
  10. <loading v-if="tabKey===1" class="w-full h-full overflow-auto" :loading-state="loadingState" tip="获取图片中">
  11. <div class="img-viewBox" :style="imgBoxStyle" ref="imgViewBox">
  12. <div
  13. v-for="item in images"
  14. :key="item.path"
  15. :class="`img-viewItem
  16. ${item.filePath === imgUrl?'img-viewItem-select bg-red-300':'bg-gray-400'}
  17. ${fileType === fileTypes.svg?'svgImage':''}
  18. `"
  19. :style="imgItemStyle"
  20. @click="selectImg(item)"
  21. >
  22. <img v-if="fileType === fileTypes.image" class="w-auto h-full" :src="item.filePath" alt="item.fileName">
  23. <!-- icon 类型-->
  24. <svg-icon v-else-if="fileType === fileTypes.svg" :svgHref="item.filePath"></svg-icon>
  25. </div>
  26. </div>
  27. <template v-slot:loadFail>
  28. <div class="w-full h-full flex justify-center items-center flex-col" >
  29. <h2 class="text-2xl text-red-700">{{loadingMessage}}</h2>
  30. </div>
  31. </template>
  32. </loading>
  33. <!-- 文件上传部分 -->
  34. <div
  35. v-if="tabKey===2"
  36. class="w-full h-full flex flex-col ">
  37. <div class="w-full h-32 rounded
  38. border overflow-hidden flex-shrink">
  39. <upload-file
  40. :type="fileType"
  41. :multiple="true"
  42. @change="uploadChangeHandle"
  43. > </upload-file>
  44. </div>
  45. <div class="w-full h-full overflow-auto">
  46. <div
  47. v-for="file in fileList"
  48. class="w-full h-64 rounded mt-2
  49. border flex relative px-2">
  50. <div class="w-full absolute bottom-0 left-0"
  51. v-if="file.status !== fileState.waiting">
  52. <a-progress :show-info="file.showInfo" :percent="file.percent" />
  53. </div>
  54. <div class="w-1/3 h-full p-4 relative rounded overflow-hidden">
  55. <image-viewer :src="file.url"/>
  56. </div>
  57. <div class="w-2/3 h-full flex items-center relative justify-between">
  58. <div>
  59. <!-- 状态提示 -->
  60. <div class="w-full">
  61. <a-alert :message="file.showInfo_message"
  62. :type="file.showInfo_type"
  63. show-icon />
  64. </div>
  65. <span>
  66. {{file.name}}
  67. </span>
  68. </div>
  69. <a-button-group>
  70. <a-button :disabled="file.status === fileState.uploading || file.status === fileState.success"
  71. :loading="file.status === fileState.uploading" >删除</a-button>
  72. <a-button :disabled="file.status === fileState.uploading || file.status === fileState.success"
  73. :loading="file.status === fileState.uploading"
  74. class="ml-2" @click="uploadFileItem(file)">上传</a-button>
  75. </a-button-group>
  76. </div>
  77. </div>
  78. </div>
  79. </div>
  80. </div>
  81. <div class="p-header w-full mt-2">
  82. <a-button @click="close" type="danger">X</a-button>
  83. <a-button class="ml-2" type="primary" @click="selectNowImg" :disabled="!imgUrl">选择当前照片</a-button>
  84. <!-- 移除选择的照片 -->
  85. <a-button class="ml-2" v-show="imgUrl" type="danger" @click="removeFileHandle">移除选择的照片</a-button>
  86. </div>
  87. </div>
  88. </template>
  89. <script>
  90. import {handle} from "~/until/handle";
  91. import Loading from "~/components/public/loading";
  92. import {db_base} from "../../map/dbField_esm";
  93. import {rCode} from "../../map/rcodeMap_esm";
  94. import UploadFile from "./uploadFile.vue";
  95. import ImageViewer from "./imageViewer.vue";
  96. import domTool from "~/until/domTool";
  97. const fileState = {
  98. waiting: 'waiting',
  99. uploading: 'uploading',
  100. success: 'success',
  101. fail: 'fail'
  102. }
  103. export default {
  104. name: "imageTable",
  105. components: {ImageViewer, UploadFile, Loading},
  106. props: {
  107. imgHeight: {
  108. type: Number,
  109. default: 150
  110. },
  111. lineItem: {
  112. type: Number,
  113. default: 5
  114. },
  115. // 间隔,单位px
  116. gap: {
  117. type: Number,
  118. default: 5
  119. },
  120. // 文件类型 1图片 2视频 3音频 4svg 文件
  121. fileType: {
  122. type: Number,
  123. default: db_base.fileType.image
  124. }
  125. },
  126. data(){
  127. return {
  128. uploadUrl: `/api/base/fileUp`,
  129. tabKey: 1,
  130. imgUrl:'',
  131. fileData: {},
  132. loadingState: 0,
  133. loadingMessage: '',
  134. searchKey: '',
  135. fileState: fileState,
  136. fileTypes: db_base.fileType,
  137. fileList: [],
  138. images: [],
  139. imgBoxStyle: '',
  140. imgItemStyle: '',
  141. }
  142. },
  143. async mounted() {
  144. // this.comStyle();
  145. await this.loadImage();
  146. // 监听resize
  147. },
  148. methods:{
  149. close(){
  150. this.$emit('cancel')
  151. },
  152. // 选择图片
  153. selectNowImg(){
  154. if(!this.imgUrl){
  155. return this.$message.warn('请选择图片')
  156. }
  157. this.$emit('ok',this.fileData);
  158. },
  159. comStyle(){
  160. this.$nextTick(()=>{
  161. let el_imgViewBox = this.$refs.imgViewBox;
  162. let res = domTool.comDomStyle(el_imgViewBox,this.lineItem,this.gap);
  163. if(res === -1){
  164. return this.$message.error('计算样式失败,元素不存在');
  165. }
  166. let {boxPadding,itemStyle} = res;
  167. this.imgBoxStyle = boxPadding;
  168. this.imgItemStyle = itemStyle + `;height:${this.imgHeight}px`;
  169. });
  170. },
  171. async loadImage(){
  172. this.loadingState = 0;
  173. let url = '/api/base/files';
  174. let params = {
  175. type: this.fileType + 1,
  176. key: this.searchKey
  177. };
  178. let [err,res] = await handle(this.$axios.get(url,{params}));
  179. if(err){
  180. this.loadingState = 2;
  181. this.loadingMessage = '获取图片失败';
  182. return console.log(err);
  183. }
  184. let result = res.data;
  185. if(result.code === rCode.OK){
  186. this.loadingState = 1;
  187. this.comStyle();
  188. this.images = result.data;
  189. }else{
  190. this.loadingState = 2;
  191. this.loadingMessage = `获取图片失败${result.msg}`;
  192. this.$message.error(result.msg);
  193. return {}
  194. }
  195. },
  196. async uploadChangeHandle(files){
  197. console.log(files);
  198. console.log(`files is ${files.length}`);
  199. // 文件预览
  200. for(let i = 0;i<files.length;i++){
  201. let file = files[i];
  202. let [err,fileUrl] = await handle(this.fileToPreview(file));
  203. if(err){
  204. this.$message.warn(`文件${file.name}预览失败`);
  205. // 文件转换失败
  206. return console.log(err);
  207. }
  208. this.fileList.push({
  209. file: file,
  210. uid: file.uid,
  211. name: file.name,
  212. status: fileState.waiting,
  213. percent: 0,
  214. showInfo: false,
  215. showInfo_message: '点击按钮进行上传',
  216. showInfo_type: 'info',
  217. url: fileUrl
  218. });
  219. }
  220. },
  221. fileToPreview(file){
  222. return new Promise((resolve, reject) => {
  223. let reader = new FileReader();
  224. reader.readAsDataURL(file);
  225. reader.onload = function (e) {
  226. resolve(e.target.result);
  227. };
  228. reader.onerror = function (e) {
  229. reject(e);
  230. };
  231. });
  232. },
  233. callback(key) {
  234. console.log(key);
  235. this.tabKey = key;
  236. },
  237. // 选择图片
  238. selectImg(fileData){
  239. console.log(`selectImg ${fileData.filePath} fileId is ${fileData.fileId}`);
  240. this.imgUrl = fileData.filePath;
  241. this.fileData = fileData;
  242. },
  243. // 编辑图片信息
  244. editImg(fileData){
  245. console.log(`editImg ${fileData.filePath} fileId is ${fileData.fileId}`);
  246. },
  247. async uploadFileItem(file){
  248. if(!file || !file.file || file.status === fileState.fail){
  249. return this.$message.error('调用异常,已经阻止上传');
  250. }
  251. file.showInfo = true;
  252. file.status = fileState.uploading;
  253. file.percent = 0;
  254. file.showInfo_message = '上传中';
  255. file.showInfo_type = 'info';
  256. let form = new FormData();
  257. form.append('file',file.file);
  258. let uploadUrl = this.uploadUrl;
  259. uploadUrl += `?type=${this.fileType}`;
  260. let [err,res] = await handle(this.$axios.post(uploadUrl, form,{
  261. onUploadProgress: (progressEvent) => {
  262. file.percent = Math.round((progressEvent.loaded * 100) / progressEvent.total) || 0;
  263. }
  264. }));
  265. if(err){
  266. file.status = fileState.fail;
  267. file.showInfo_message = `上传失败,${err.message}`;
  268. file.showInfo_type = 'error';
  269. return console.log(err);
  270. }
  271. let result = res.data;
  272. if(result.code === rCode.OK) {
  273. file.status = fileState.success;
  274. file.showInfo_message = `文件上传成功`;
  275. file.showInfo_type = 'success';
  276. this.$message.success('上传成功');
  277. await this.loadImage();
  278. }else{
  279. file.status = fileState.fail;
  280. file.showInfo_message = `上传失败,${err.message}`;
  281. file.showInfo_type = 'error';
  282. this.$message.error(result.msg);
  283. }
  284. },
  285. async updateFileItem(updateData){
  286. },
  287. async removeFileHandle(){
  288. let fileData = this.fileData;
  289. if(!fileData || !fileData.fileId){
  290. return this.$message.warn('暂未选择图片');
  291. }
  292. let [err,res] = await handle(this.$axios.delete(`/api/base/file/${fileData.fileId}`));
  293. if(err){
  294. this.$message.error('删除图像资源失败');
  295. return console.log(err);
  296. }
  297. let result = res.data;
  298. if(result.code === rCode.OK) {
  299. this.$message.success('删除图像资源成功');
  300. this.imgUrl = '';
  301. this.fileData = {};
  302. await this.loadImage();
  303. }else{
  304. this.$message.error(result.msg);
  305. }
  306. }
  307. },
  308. }
  309. </script>
  310. <style scoped>
  311. .p-header{
  312. height:35px;
  313. }
  314. .p-con {
  315. height: calc(100% - 80px);
  316. }
  317. .img-viewBox{
  318. width: calc(100% - 15px);
  319. display: flex;
  320. flex-wrap: wrap;
  321. justify-content: flex-start;
  322. overflow: auto;
  323. }
  324. .svgImage{
  325. display: flex;
  326. color: #1a1a1a;
  327. font-size: 65px;
  328. justify-content: center;
  329. align-items: center;
  330. }
  331. .img-viewItem{
  332. cursor: pointer;
  333. flex-shrink: 0;
  334. transition: all 0.5s;
  335. display: flex;
  336. justify-content: center;
  337. }
  338. .img-viewItem-select{
  339. border: 2px solid #01eef5;
  340. box-shadow: 0 0 2px #fff;
  341. }
  342. </style>