刘洋 2 жил өмнө
parent
commit
140ad56188

+ 14 - 0
src/components/common/ContentEditAble.vue

@@ -7,6 +7,7 @@
     @input="inputChange"
     @blur="inputChange"
     @click="$emit('click', $event)"
+    @paste="paste"
   >
   </component>
 </template>
@@ -36,6 +37,19 @@ const contentValue = useVModel(props, 'modelValue')
 
 const contenteditableEle = ref<HTMLElement | null>()
 
+const paste = (event: any) => {
+  let e = event || window.event
+  // 阻止默认粘贴
+  e.preventDefault()
+  // 粘贴事件有一个clipboardData的属性,提供了对剪贴板的访问
+  // clipboardData的getData(fomat) 从剪贴板获取指定格式的数据
+  var text = (e.originalEvent || e).clipboardData.getData('text/plain') || prompt('在这里输入文本')
+  //清除回车
+  text = text.replace(/\[\d+\]|\n|\r/gi, '')
+  // 插入
+  document.execCommand('insertText', false, text)
+}
+
 function updateContent(content: string) {
   if (contenteditableEle.value) {
     contenteditableEle.value.innerHTML = content

+ 8 - 1
src/components/element/BaseDialog.vue

@@ -13,7 +13,14 @@
     <slot />
     <template v-if="props.footer !== false" #footer>
       <template v-if="!!props.canResize">
-        <div v-if="props.canResize == 'can-resize2'" v-dialogResizeImg="props.canResize" class="foot-box">
+        <div
+          v-if="props.canResize == 'can-resize2' || props.canResize == 'can-resize22'"
+          v-dialogResizeImg="props.canResize"
+          class="foot-box"
+        >
+          <slot name="footer"></slot>
+        </div>
+        <div v-else-if="props.canResize == 'can-resize3'" v-dialogResizeStandard="props.canResize" class="foot-box">
           <slot name="footer"></slot>
         </div>
         <div v-else v-dialogResize="props.canResize" class="foot-box">

+ 2 - 1
src/components/shared/ImagePreview.vue

@@ -3,7 +3,7 @@
     v-model="visible"
     less
     title="试卷预览"
-    :can-resize="'can-resize2'"
+    :can-resize="resizeKey ? resizeKey : 'can-resize2'"
     :modal="false"
     class="preview-dialog"
   >
@@ -21,6 +21,7 @@ const props = defineProps<{
   modelValue: boolean
   url?: string
   isBig?: boolean
+  resizeKey?: string
 }>()
 const visible = useVModel(props)
 </script>

+ 35 - 2
src/components/shared/MarkHeader.vue

@@ -34,8 +34,17 @@
       </div> -->
     </div>
 
-    <base-dialog v-model="standardVisible" title="评分标准" width="40vw" center :footer="false">
-      <iframe style="width: 100%; height: 50vh" :src="standardRes?.url" alt="" />
+    <base-dialog
+      v-model="standardVisible"
+      class="standard-dialog"
+      :can-resize="'can-resize3'"
+      title="评分标准"
+      modal-class="no-mask"
+      center
+      :modal="false"
+    >
+      <div id="my-iframe-mask"></div>
+      <iframe style="width: 100%; height: 100%; prevent-events: pointer" :src="standardRes?.url" alt="" />
     </base-dialog>
   </div>
 </template>
@@ -383,3 +392,27 @@ fetchStandard()
   }
 }
 </style>
+<style lang="scss">
+.standard-dialog {
+  display: flex;
+  flex-direction: column;
+  .el-dialog__body {
+    flex: 1;
+    padding: 2px !important;
+    position: relative;
+    max-height: 150vh !important;
+  }
+  .el-dialog__footer {
+    padding: 0 !important;
+  }
+  #my-iframe-mask {
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    top: 0;
+    z-index: 10;
+    display: none;
+  }
+}
+</style>

+ 7 - 2
src/components/shared/message/MessageHistory.vue

@@ -9,11 +9,16 @@
           <span class="m-r-base user-name">{{ message.sendUserName }}</span>
           <span class="message-time">{{ message.sendTime }}</span>
         </div>
-        <pre class="message-info-content" @click="onContentClick" v-html="message.content"></pre>
+        <div class="message-info-content" @click="onContentClick" v-html="message.content"></div>
       </div>
     </template>
   </div>
-  <image-preview v-model="previewModalVisible" :url="paperPath" :is-big="true"></image-preview>
+  <image-preview
+    v-model="previewModalVisible"
+    resize-key="can-resize22"
+    :url="paperPath"
+    :is-big="true"
+  ></image-preview>
 </template>
 
 <script setup lang="ts" name="MessageHistory">

+ 6 - 1
src/components/shared/message/MessageList.vue

@@ -50,7 +50,12 @@
       <message-history v-if="showHistory" :send-user-id="currentMessage?.sendUserId"></message-history>
     </div>
   </div>
-  <image-preview v-model="previewModalVisible" :url="paperPath" :is-big="true"></image-preview>
+  <image-preview
+    v-model="previewModalVisible"
+    resize-key="can-resize22"
+    :url="paperPath"
+    :is-big="true"
+  ></image-preview>
 </template>
 
 <script setup lang="ts" name="MessageList">

+ 14 - 9
src/components/shared/message/MessageSend.vue

@@ -54,7 +54,12 @@
       ></message-history>
     </div>
   </div>
-  <image-preview v-model="previewModalVisible" :url="props.paperPath || ''" :is-big="true"></image-preview>
+  <image-preview
+    v-model="previewModalVisible"
+    resize-key="can-resize22"
+    :url="props.paperPath || ''"
+    :is-big="true"
+  ></image-preview>
 </template>
 
 <script setup lang="tsx" name="MessageSend">
@@ -197,14 +202,14 @@ const onCheckChange = () => {
 }
 
 watch(messageContent, () => {
-  let reg = /<span class=\"pointer inline link-button\" contenteditable=\"false\" data-path=.*>查看试卷<\/span>/g
-  let arr = messageContent.value.match(reg)
-  let text = messageContent.value.replace(reg, '【查看试卷临时替换字符】')
-  text = transHtmlContent(text)
-  if (arr && arr.length) {
-    text = text.replace('【查看试卷临时替换字符】', arr[0])
-  }
-  messageContent.value = text
+  // let reg = /<span class=\"pointer inline link-button\" contenteditable=\"false\" data-path=.*>查看试卷<\/span>/g
+  // let arr = messageContent.value.match(reg)
+  // let text = messageContent.value.replace(reg, '【查看试卷临时替换字符】')
+  // text = transHtmlContent(text)
+  // if (arr && arr.length) {
+  //   text = text.replace('【查看试卷临时替换字符】', arr[0])
+  // }
+  // messageContent.value = text
   nextTick(() => {
     const paperButton = document.querySelector(`.content-edit-able [data-path="${props.paperPath}"]`)
     sendedPaper.value = !!paperButton

+ 27 - 19
src/directives/dialogResizeImg.ts

@@ -3,37 +3,50 @@ export const dialogResizeImg = {
     const bValue = binding.value
     const localKeyMap: any = {
       positions: {
-        'can-resize': 'cet-keyboard-positions',
         'can-resize2': 'cet-preview-positions',
+        'can-resize22': 'cet-preview2-positions',
       },
       resize: {
-        'can-resize': 'cet-keyboard-resize',
         'can-resize2': 'cet-preview-resize',
+        'can-resize22': 'cet-preview2-resize',
       },
     }
     const resizeEvent = new CustomEvent('drag-resize', {
       detail: '尺寸变化',
       bubbles: false,
     })
+    const keyboardPositions = localStorage.getItem(localKeyMap.positions[bValue])
+    const keyboardResize = localStorage.getItem(localKeyMap.resize[bValue])
     // 初始化不最大化
     el.fullscreen = false
     // 弹框可拉伸最小宽高
-    const minWidth = binding.value === 'can-resize2' ? 290 : 336
+    const minWidth = 290
     const maxHeight = window.innerHeight
-    // const minHeight = 290
-    // 当前宽高
-    const nowWidth = minWidth
-    // eslint-disable-next-line no-unused-vars
-    // const nowHight = minHeight
-    // 当前顶部高度
-    const nowMarginTop = 0
-    // 获取弹框头部(这部分可双击全屏)
-    const hasSetBodyHight = false
+
     // 弹窗
     const dragDom: any = document.querySelector('.' + binding.value)
     const dialogHeaderEl = dragDom.querySelector('.el-dialog__header')
     const img = dragDom.querySelector('.small-img')
-    let ratio = 1
+
+    img.onload = function () {
+      // dragDom.style.width = img.clientWidth + 'px'
+      if (!keyboardResize) {
+        const compareHeight = bValue === 'can-resize22' ? parseInt(maxHeight * 0.7 + '') : parseInt(maxHeight / 2 + '')
+        console.log('compareHeight:', compareHeight)
+        console.log('img.clientHeight:', img.clientHeight)
+        const ratio = (img.clientWidth + 4) / (img.clientHeight + 48)
+        if (img.clientHeight + 48 > compareHeight) {
+          const dragDomH = compareHeight
+          // dragDom.style.height = dragDomH + 'px'
+          dragDom.style.width = dragDomH * ratio + 'px'
+          console.log('dragDom.style.width:', dragDom.style.width)
+        }
+      }
+    }
+    img.onerror = function () {
+      dragDom.style.width = minWidth + 'px'
+    }
+
     // console.log('img', getComputedStyle(img).width)
 
     el.style.overflow = 'initial'
@@ -42,8 +55,6 @@ export const dialogResizeImg = {
     // dragDom.style.overflow = 'auto'
     dragDom.style.background = '#fff'
 
-    const keyboardPositions = localStorage.getItem(localKeyMap.positions[bValue])
-    const keyboardResize = localStorage.getItem(localKeyMap.resize[bValue])
     if (keyboardPositions) {
       dragDom.style.left = JSON.parse(keyboardPositions).left || 0
       dragDom.style.top = JSON.parse(keyboardPositions).top || 0
@@ -57,11 +68,8 @@ export const dialogResizeImg = {
       //   dragDom.style.height = JSON.parse(keyboardResize).height || 'auto'
     } else {
       //   dragDom.style.height = maxHeight / 2 + 'px'
-      dragDom.style.width = '290px'
+      // dragDom.style.width = '290px'
     }
-    setTimeout(() => {
-      ratio = dragDom.clientHeight / dragDom.clientWidth
-    }, 20)
 
     // 清除选择头部文字效果
     // eslint-disable-next-line no-new-func

+ 181 - 0
src/directives/dialogResizeStandard.ts

@@ -0,0 +1,181 @@
+export const dialogResizeStandard = {
+  mounted(el: any, binding: any, vnode: any) {
+    const bValue = binding.value
+    const localKeyMap: any = {
+      positions: {
+        'can-resize3': 'cet-standard-positions',
+      },
+      resize: {
+        'can-resize3': 'cet-standard-resize',
+      },
+    }
+    const resizeEvent = new CustomEvent('drag-resize', {
+      detail: '尺寸变化',
+      bubbles: false,
+    })
+    // 初始化不最大化
+    el.fullscreen = false
+    const winHeight = window.innerHeight
+    // 弹框可拉伸最小宽高
+    const minWidth = 400
+    const minHeight = winHeight / 2
+
+    // 弹窗
+    const dragDom: any = document.querySelector('.' + binding.value)
+    const dialogHeaderEl = dragDom.querySelector('.el-dialog__header')
+
+    el.style.overflow = 'initial'
+    dragDom.className += ' el-drag-dialog'
+    // 给弹窗加上overflow auto;不然缩小时框内的标签可能超出dialog;
+    // dragDom.style.overflow = 'auto'
+    dragDom.style.background = '#fff'
+
+    const keyboardPositions = localStorage.getItem(localKeyMap.positions[bValue])
+    const keyboardResize = localStorage.getItem(localKeyMap.resize[bValue])
+    if (keyboardPositions) {
+      dragDom.style.left = JSON.parse(keyboardPositions).left || 0
+      dragDom.style.top = JSON.parse(keyboardPositions).top || 0
+    }
+
+    if (keyboardResize) {
+      const localW = JSON.parse(keyboardResize).width
+      const localH = JSON.parse(keyboardResize).height
+      localW && (dragDom.style.width = localW)
+      localH && (dragDom.style.height = localH)
+    } else {
+      dragDom.style.height = minHeight + 100 + 'px'
+      dragDom.style.width = '800px'
+    }
+
+    // 清除选择头部文字效果
+    // eslint-disable-next-line no-new-func
+    dialogHeaderEl.onselectstart = new Function('return false')
+    // 头部加上可拖动cursor
+    dialogHeaderEl.style.cursor = 'move'
+
+    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
+    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
+
+    // 头部插入最大化最小化元素
+    const maxMin = document.createElement('button')
+    maxMin.className += ' el-dialog__headerbtn el-dialog__minmax'
+    maxMin.style.right = '40px'
+    maxMin.style.color = '#ffffff'
+    maxMin.title = el.fullscreen ? '还原' : '最大化'
+    maxMin.innerHTML =
+      '<i class=' +
+      (el.fullscreen ? '"el-icon-crop"' : '"el-icon-full-screen"') +
+      ' onMouseOver="this.style.color=\'#409EFF\'" onMouseOut="this.style.color=\'inherit\'"></i>'
+    dialogHeaderEl.insertBefore(maxMin, dialogHeaderEl.childNodes[1])
+    const moveDown = (e: any) => {
+      // 鼠标按下,计算当前元素距离可视区的距离
+      const disX = e.clientX - dialogHeaderEl.offsetLeft
+      const disY = e.clientY - dialogHeaderEl.offsetTop
+
+      // 获取到的值带px 正则匹配替换
+      let styL: any, styT: any
+
+      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
+      if (sty.left.includes('%')) {
+        styL = +document.body.clientWidth * (+sty.left.replace(/\\%/g, '') / 100)
+        styT = +document.body.clientHeight * (+sty.top.replace(/\\%/g, '') / 100)
+      } else {
+        styL = +sty.left.replace(/\px/g, '')
+        styT = +sty.top.replace(/\px/g, '')
+      }
+
+      document.onmousemove = function (e) {
+        // 通过事件委托,计算移动的距离
+        const l = e.clientX - disX
+        const t = e.clientY - disY
+
+        // 移动当前元素
+        dragDom.style.left = `${l + styL}px`
+        dragDom.style.top = `${t + styT}px`
+
+        // 将此时的位置传出去
+        // binding.value({x:e.pageX,y:e.pageY})
+      }
+
+      document.onmouseup = function (e) {
+        document.onmousemove = null
+        document.onmouseup = null
+        console.log('dragDom.style.left:', dragDom.style.left, dragDom.style.top)
+        localStorage.setItem(
+          localKeyMap.positions[bValue],
+          JSON.stringify({
+            left: dragDom.style.left || 0,
+            top: dragDom.style.top || 0,
+          })
+        )
+      }
+    }
+    dialogHeaderEl.onmousedown = moveDown
+
+    // 点击放大缩小效果
+    // maxMin.onclick = setMaxMin
+    // 双击头部效果
+    // dialogHeaderEl.ondblclick = setMaxMin
+    // 拉伸
+    const resizeEl = document.createElement('div')
+    dragDom.appendChild(resizeEl)
+    // 在弹窗右下角加上一个10-10px的控制块
+    resizeEl.style.cursor = 'se-resize'
+    resizeEl.style.position = 'absolute'
+    resizeEl.style.height = '10px'
+    resizeEl.style.width = '10px'
+    resizeEl.style.border = '3px solid transparent'
+    resizeEl.style.borderRightColor = '#333'
+    resizeEl.style.borderBottomColor = '#333'
+    resizeEl.style.right = '0px'
+    resizeEl.style.bottom = '0px'
+    resizeEl.style.zIndex = '99'
+    // 鼠标拉伸弹窗
+    resizeEl.onmousedown = (e) => {
+      // 记录初始x位置
+      const clientX = e.clientX
+      // 鼠标按下,计算当前元素距离可视区的距离
+      const disX = e.clientX - resizeEl.offsetLeft
+      const disY = e.clientY - resizeEl.offsetTop
+      const iframeMask = document.getElementById('my-iframe-mask')
+      if (iframeMask) {
+        iframeMask.style.display = 'block'
+      }
+      document.onmousemove = function (e) {
+        e.preventDefault() // 移动时禁用默认事件
+        // 通过事件委托,计算移动的距离
+        const x = e.clientX - disX + (e.clientX - clientX) // 这里 由于elementUI的dialog控制居中的,所以水平拉伸效果是双倍
+        const y = e.clientY - disY
+        // 比较是否小于最小宽高
+        dragDom.style.width = x > minWidth ? `${x}px` : minWidth + 'px'
+        dragDom.style.height = y > minHeight ? `${y}px` : minHeight + 'px'
+        // dragDom.style.width = `${x}px`
+        // dragDom.style.height = `${y}px`
+        // if (!hasSetBodyHight) {
+        //   const footerHeight =
+        //     dragDom.querySelector('.el-dialog__footer') && dragDom.querySelector('.el-dialog__footer').offsetHeight
+        //   dragDom.querySelector('.el-dialog__body').style.height =
+        //     'calc(100% - ' + (dialogHeaderEl.offsetHeight + footerHeight) + 'px)'
+        //   hasSetBodyHight = true
+        // }
+      }
+      // 拉伸结束
+      document.onmouseup = function (e) {
+        document.onmousemove = null
+        document.onmouseup = null
+        localStorage.setItem(
+          localKeyMap.resize[bValue],
+          JSON.stringify({
+            width: dragDom.style.width || 'auto',
+            height: dragDom.style.height || 'auto',
+          })
+        )
+        el.dispatchEvent(resizeEvent)
+        const iframeMask = document.getElementById('my-iframe-mask')
+        if (iframeMask) {
+          iframeMask.style.display = 'none'
+        }
+      }
+    }
+  },
+}

+ 2 - 0
src/directives/index.ts

@@ -1,7 +1,9 @@
 import { dialogResize } from './dialogResize'
 import { dialogResizeImg } from './dialogResizeImg'
+import { dialogResizeStandard } from './dialogResizeStandard'
 
 export function setupDirectives(app: any) {
   app.directive('dialogResize', dialogResize)
   app.directive('dialogResizeImg', dialogResizeImg)
+  app.directive('dialogResizeStandard', dialogResizeStandard)
 }

+ 10 - 2
src/modules/admin-subject/manage/index.vue

@@ -8,7 +8,15 @@
     </div>
     <div class="flex-1 p-base">
       <el-card shadow="never">
-        <base-table border stripe size="small" :columns="columns" :data="data" @row-dblclick="onViewSubjectStruct">
+        <base-table
+          border
+          stripe
+          size="small"
+          :columns="columns"
+          :data="data"
+          :show-overflow-tooltip="false"
+          @row-dblclick="onViewSubjectStruct"
+        >
           <template #column-operation="{ row }">
             <el-button type="primary" link @click="onEdit(row)">编辑</el-button>
             <el-popconfirm
@@ -81,7 +89,7 @@ const columns: EpTableColumn<ExtractMultipleApiResponse<'getSubjectList'>>[] = [
         row.code
       ) : (
         <p style="display:flex;align-items:center">
-          <img style="height:10px;margin-right:3px;" src={jiaImg} />
+          <img style="height:10px;width:10px;margin-right:3px;" src={jiaImg} />
           <span>{row.code}</span>
         </p>
       )