imageTable.vue 10 KB

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