mirror of
				https://github.com/Powerful-517/yys-editor.git
				synced 2025-11-04 05:29:50 +00:00 
			
		
		
		
	富文本复制粘贴,水印自动扩展,其他命名优化
This commit is contained in:
		@@ -5,8 +5,10 @@ import Watermark from './components/Watermark.vue' // 引入 Watermark 组件
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <main id="main-container">
 | 
			
		||||
    <Yys />
 | 
			
		||||
    <Watermark text="示例水印" font="30px Arial" color="rgba(184, 184, 184, 0.3)" angle=-20 /> <!-- 添加 Watermark 组件 -->
 | 
			
		||||
    <!-- 添加 Watermark 组件 -->
 | 
			
		||||
    <Watermark text="示例水印" font="30px Arial" color="rgba(184, 184, 184, 0.3)" angle=-20 >
 | 
			
		||||
      <Yys />
 | 
			
		||||
    </Watermark>
 | 
			
		||||
  </main>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -15,7 +17,8 @@ import Watermark from './components/Watermark.vue' // 引入 Watermark 组件
 | 
			
		||||
#main-container {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100vh; /* 视口高度 */
 | 
			
		||||
  min-height: 100vh; /* 允许容器扩展 */
 | 
			
		||||
  //position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 如果 Yys 组件需要特定的高度或布局,可以根据需要调整 */
 | 
			
		||||
 
 | 
			
		||||
@@ -18,15 +18,15 @@
 | 
			
		||||
    <el-form :model="shikigami" label-width="120px">
 | 
			
		||||
      <el-form-item label="等级要求">
 | 
			
		||||
        <el-radio-group v-model="shikigami.levelRequired" class="ml-4">
 | 
			
		||||
          <el-radio label="40" size="large">40</el-radio>
 | 
			
		||||
          <el-radio label="0" size="large">献祭</el-radio>
 | 
			
		||||
          <el-radio value="40" size="large">40</el-radio>
 | 
			
		||||
          <el-radio value="0" size="large">献祭</el-radio>
 | 
			
		||||
        </el-radio-group>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="技能要求">
 | 
			
		||||
        <el-radio-group v-model="shikigami.skillRequiredMode" class="ml-4">
 | 
			
		||||
          <el-radio label="all" size="large">全满</el-radio>
 | 
			
		||||
          <el-radio label="111" size="large">111</el-radio>
 | 
			
		||||
          <el-radio label="custom" size="large">自定义</el-radio>
 | 
			
		||||
          <el-radio value="all" size="large">全满</el-radio>
 | 
			
		||||
          <el-radio value="111" size="large">111</el-radio>
 | 
			
		||||
          <el-radio value="custom" size="large">自定义</el-radio>
 | 
			
		||||
        </el-radio-group>
 | 
			
		||||
        <div v-if="shikigami.skillRequiredMode === 'custom'" style="display: flex; flex-direction: row; width: 100%;">
 | 
			
		||||
          <el-select v-for="(value, key, index) in shikigami.skillRequired" :placeholder="value"
 | 
			
		||||
@@ -54,10 +54,10 @@
 | 
			
		||||
                class="image"
 | 
			
		||||
                @click="openYuhunSelect(index)"
 | 
			
		||||
            />
 | 
			
		||||
<!--            <img style="width: 50px;height: 50px" v-if="shikigami.yuhun.yuhunSetEffect.length>0"-->
 | 
			
		||||
<!--                 :src="shikigami.yuhun.yuhunSetEffect[0].avatar" class="image"/>-->
 | 
			
		||||
<!--            <img style="width: 50px;height: 50px" v-if="shikigami.yuhun.yuhunSetEffect.length>1"-->
 | 
			
		||||
<!--                 :src="shikigami.yuhun.yuhunSetEffect[1].avatar" class="image"/>-->
 | 
			
		||||
            <!--            <img style="width: 50px;height: 50px" v-if="shikigami.yuhun.yuhunSetEffect.length>0"-->
 | 
			
		||||
            <!--                 :src="shikigami.yuhun.yuhunSetEffect[0].avatar" class="image"/>-->
 | 
			
		||||
            <!--            <img style="width: 50px;height: 50px" v-if="shikigami.yuhun.yuhunSetEffect.length>1"-->
 | 
			
		||||
            <!--                 :src="shikigami.yuhun.yuhunSetEffect[1].avatar" class="image"/>-->
 | 
			
		||||
 | 
			
		||||
            <el-button type="primary" @click="openYuhunSelect(-1)">
 | 
			
		||||
              <el-icon :size="20">
 | 
			
		||||
@@ -281,12 +281,22 @@ const openYuhunSelect = (index) => {
 | 
			
		||||
const closeYuhunSelect = () => showYuhunSelect.value = false
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const updateYuhunSelect = (yuhun) => {
 | 
			
		||||
const updateYuhunSelect = (yuhun, operator) => {
 | 
			
		||||
  showYuhunSelect.value = false
 | 
			
		||||
  if(yuhunIndex.value >=0)
 | 
			
		||||
    shikigami.value.yuhun.yuhunSetEffect[yuhunIndex.value] = (JSON.parse(JSON.stringify(yuhun)))
 | 
			
		||||
  else
 | 
			
		||||
    shikigami.value.yuhun.yuhunSetEffect.push(JSON.parse(JSON.stringify(yuhun)))
 | 
			
		||||
  //Update
 | 
			
		||||
  if (operator == "Update") {
 | 
			
		||||
    if (yuhunIndex.value >= 0)
 | 
			
		||||
      shikigami.value.yuhun.yuhunSetEffect[yuhunIndex.value] = (JSON.parse(JSON.stringify(yuhun)))
 | 
			
		||||
    else
 | 
			
		||||
      shikigami.value.yuhun.yuhunSetEffect.push(JSON.parse(JSON.stringify(yuhun)))
 | 
			
		||||
  }
 | 
			
		||||
  //Delete
 | 
			
		||||
  else if (operator == "Remove") {
 | 
			
		||||
    if (yuhunIndex.value >= 0) {
 | 
			
		||||
      // 使用splice方法移除指定位置的御魂
 | 
			
		||||
      shikigami.value.yuhun.yuhunSetEffect.splice(yuhunIndex.value, 1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div ref="watermarkContainer" class="watermark-container"></div>
 | 
			
		||||
  <div class="watermark-container">
 | 
			
		||||
    <!-- 插槽内容(即 Yys 组件) -->
 | 
			
		||||
    <slot></slot>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
@@ -12,7 +15,7 @@ const props = defineProps({
 | 
			
		||||
  },
 | 
			
		||||
  font: {
 | 
			
		||||
    type: String,
 | 
			
		||||
    default: '20px Arial'
 | 
			
		||||
    default: '30px Arial'
 | 
			
		||||
  },
 | 
			
		||||
  color: {
 | 
			
		||||
    type: String,
 | 
			
		||||
@@ -24,14 +27,11 @@ const props = defineProps({
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const watermarkContainer = ref(null);
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  createWatermark();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const createWatermark = () => {
 | 
			
		||||
  const container = watermarkContainer.value;
 | 
			
		||||
  const canvas = document.createElement('canvas');
 | 
			
		||||
  const ctx = canvas.getContext('2d');
 | 
			
		||||
 | 
			
		||||
@@ -65,29 +65,43 @@ const createWatermark = () => {
 | 
			
		||||
  // 将 canvas 转换为 base64 图像
 | 
			
		||||
  const watermarkUrl = canvas.toDataURL('image/png');
 | 
			
		||||
 | 
			
		||||
  // 创建一个 div 并设置背景图
 | 
			
		||||
  const watermarkDiv = document.createElement('div');
 | 
			
		||||
  watermarkDiv.style.position = 'absolute';
 | 
			
		||||
  watermarkDiv.style.top = '0';
 | 
			
		||||
  watermarkDiv.style.left = '0';
 | 
			
		||||
  watermarkDiv.style.width = '100%';
 | 
			
		||||
  watermarkDiv.style.height = '100%';
 | 
			
		||||
  watermarkDiv.style.backgroundImage = `url(${watermarkUrl})`;
 | 
			
		||||
  watermarkDiv.style.backgroundRepeat = 'repeat';
 | 
			
		||||
  watermarkDiv.style.pointerEvents = 'none'; // 确保水印不会干扰用户交互
 | 
			
		||||
  // 获取父容器并应用背景图
 | 
			
		||||
  const container = document.querySelector('.watermark-container');
 | 
			
		||||
  container.style.backgroundImage = `url(${watermarkUrl})`;
 | 
			
		||||
  container.style.backgroundRepeat = 'repeat';
 | 
			
		||||
 | 
			
		||||
  // 将水印 div 添加到容器中
 | 
			
		||||
  container.appendChild(watermarkDiv);
 | 
			
		||||
  // 在生成水印后添加 resize 监听
 | 
			
		||||
  // const observer = new ResizeObserver(entries => {
 | 
			
		||||
  //   entries.forEach(entry => {
 | 
			
		||||
  //     container.style.backgroundImage = `url(${watermarkUrl})`;
 | 
			
		||||
  //   });
 | 
			
		||||
  // });
 | 
			
		||||
  // observer.observe(container);
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.watermark-container {
 | 
			
		||||
  position: absolute; /* 使用绝对定位 */
 | 
			
		||||
  position: relative;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  min-height: 100vh; /* 基础高度 */
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 使用伪元素添加水印背景 */
 | 
			
		||||
.watermark-container::before {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  background-image: inherit;
 | 
			
		||||
  background-repeat: repeat;
 | 
			
		||||
  pointer-events: none; /* 确保水印不会干扰用户交互 */
 | 
			
		||||
  z-index: 9999; /* 确保水印在最顶层 */
 | 
			
		||||
  //background-attachment: fixed; /* 增强覆盖效果 */
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-dialog v-model="show" :title="t('yuhunSelect')" @close="cancel">
 | 
			
		||||
    <span>当前选择:{{ current.name }}</span>
 | 
			
		||||
    <div style="display: flex; justify-content: space-between; align-items: center;">
 | 
			
		||||
      <span>当前选择:{{ current.name }}</span>
 | 
			
		||||
      <el-button type="danger" icon="Delete" round @click="remove()"></el-button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <el-tabs v-model="activeName" type="card" class="demo-tabs" @tab-click="handleTabClick">
 | 
			
		||||
      <el-tab-pane v-for="type in yuhunTypes" :key="type.name" :label="type.label" :name="type.name">
 | 
			
		||||
        <el-space wrap size="large">
 | 
			
		||||
          <div v-for="shikigami in filterShikigamiByType(activeName)" :key="shikigami.name">
 | 
			
		||||
            <el-button style="width: 100px; height: 100px;" @click="confirm(shikigami)">
 | 
			
		||||
              <img :src="shikigami.avatar" style="width: 99px; height: 99px;">
 | 
			
		||||
          <div v-for="yuhun in filterYuhunByType(activeName)" :key="yuhun.name">
 | 
			
		||||
            <el-button style="width: 100px; height: 100px;" @click="confirm(yuhun)">
 | 
			
		||||
              <img :src="yuhun.avatar" style="width: 99px; height: 99px;">
 | 
			
		||||
            </el-button>
 | 
			
		||||
          </div>
 | 
			
		||||
        </el-space>
 | 
			
		||||
@@ -16,13 +19,13 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref, watch, computed } from 'vue';
 | 
			
		||||
import {ref, watch, computed} from 'vue';
 | 
			
		||||
import shikigamiData from '../data/Shikigami.json';
 | 
			
		||||
import yuhunData from '../data/Yuhun.json';
 | 
			
		||||
import { useI18n } from 'vue-i18n'
 | 
			
		||||
import {useI18n} from 'vue-i18n'
 | 
			
		||||
 | 
			
		||||
// 获取当前的 i18n 实例
 | 
			
		||||
const { t } = useI18n()
 | 
			
		||||
const {t} = useI18n()
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  currentShikigami: {
 | 
			
		||||
@@ -38,14 +41,14 @@ const show = ref(false);
 | 
			
		||||
const activeName = ref('ALL');
 | 
			
		||||
const current = ref(props.currentShikigami);
 | 
			
		||||
const yuhunTypes = [
 | 
			
		||||
  { label: '全部', name: 'ALL' },
 | 
			
		||||
  { label: '攻击加成', name: 'Attack' },
 | 
			
		||||
  { label: '暴击', name: 'Crit' },
 | 
			
		||||
  { label: '生命加成', name: 'Health' },
 | 
			
		||||
  { label: '防御加成', name: 'Defense' },
 | 
			
		||||
  { label: '效果命中', name: 'ControlHit' },
 | 
			
		||||
  { label: '效果抵抗', name: 'ControlMiss' },
 | 
			
		||||
  { label: '首领御魂', name: 'PVE' }
 | 
			
		||||
  {label: '全部', name: 'ALL'},
 | 
			
		||||
  {label: '攻击加成', name: 'Attack'},
 | 
			
		||||
  {label: '暴击', name: 'Crit'},
 | 
			
		||||
  {label: '生命加成', name: 'Health'},
 | 
			
		||||
  {label: '防御加成', name: 'Defense'},
 | 
			
		||||
  {label: '效果命中', name: 'ControlHit'},
 | 
			
		||||
  {label: '效果抵抗', name: 'ControlMiss'},
 | 
			
		||||
  {label: '首领御魂', name: 'PVE'}
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
watch(() => props.showYuhunSelect, (newVal) => {
 | 
			
		||||
@@ -60,7 +63,7 @@ const handleTabClick = (tab) => {
 | 
			
		||||
  console.log(tab.paneName);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const filterShikigamiByType = (type) => {
 | 
			
		||||
const filterYuhunByType = (type) => {
 | 
			
		||||
  if (type.toLowerCase() === 'all') return yuhunData;
 | 
			
		||||
  return yuhunData.filter(yuhun => yuhun.type.toLowerCase() === type.toLowerCase());
 | 
			
		||||
};
 | 
			
		||||
@@ -70,6 +73,10 @@ const cancel = () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const confirm = (item) => {
 | 
			
		||||
  emit('updateYuhunSelect', JSON.parse(JSON.stringify(item)));
 | 
			
		||||
  emit('updateYuhunSelect', JSON.parse(JSON.stringify(item)), 'Update');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const remove = () => {
 | 
			
		||||
  emit('updateYuhunSelect',undefined,'Remove')
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@@ -20,42 +20,71 @@
 | 
			
		||||
    <template #item="{ element: group, index: groupIndex }">
 | 
			
		||||
      <el-row :span="24">
 | 
			
		||||
        <div>
 | 
			
		||||
          <div style="display: flex; justify-content: flex-end;" data-html2canvas-ignore="true">
 | 
			
		||||
            <el-button class="drag-handle" type="primary" icon="Rank" circle></el-button>
 | 
			
		||||
            <el-button type="danger" icon="Delete" circle @click="removeGroup(groupIndex)"></el-button>
 | 
			
		||||
            <el-button type="primary" icon="Plus" circle @click="addGroup"></el-button>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div>
 | 
			
		||||
            <draggable :list="group" item-key="name" style="display: flex; flex-direction: row; width: 20%;">
 | 
			
		||||
            <div style="display: flex; justify-content: space-between;" data-html2canvas-ignore="true">
 | 
			
		||||
              <div>
 | 
			
		||||
                <el-button type="primary" icon="CopyDocument" @click="copy(group.shortDescription)">{{ t('Copy') }}
 | 
			
		||||
                </el-button>
 | 
			
		||||
                <el-button type="primary" icon="Document" @click="paste(groupIndex,'shortDescription')">{{
 | 
			
		||||
                    t('Paste')
 | 
			
		||||
                  }}
 | 
			
		||||
                </el-button>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div>
 | 
			
		||||
                <el-button class="drag-handle" type="primary" icon="Rank" circle></el-button>
 | 
			
		||||
                <el-button type="primary" icon="Plus" circle @click="addGroup"></el-button>
 | 
			
		||||
                <el-button type="danger" icon="Delete" circle @click="removeGroup(groupIndex)"></el-button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <QuillEditor v-model:content="group.shortDescription" contentType="html" theme="snow"
 | 
			
		||||
                         :toolbar="toolbarOptions"/>
 | 
			
		||||
          </div>
 | 
			
		||||
          <!--          <div style="display: flex; justify-content: flex-end;" data-html2canvas-ignore="true">-->
 | 
			
		||||
          <!--            <el-button class="drag-handle" type="primary" icon="Rank" circle></el-button>-->
 | 
			
		||||
          <!--            <el-button type="danger" icon="Delete" circle @click="removeGroup(groupIndex)"></el-button>-->
 | 
			
		||||
          <!--            <el-button type="primary" icon="Plus" circle @click="addGroup"></el-button>-->
 | 
			
		||||
          <!--          </div>-->
 | 
			
		||||
          <div>
 | 
			
		||||
            <draggable :list="group.groupInfo" item-key="name" style="display: flex; flex-direction: row; width: 20%;">
 | 
			
		||||
              <template #item="{element : position, index:positionIndex}">
 | 
			
		||||
                <div>
 | 
			
		||||
                  <el-col>
 | 
			
		||||
                    <el-card :body-style="{ padding: '0px' } ">
 | 
			
		||||
                    <el-card :body-style="{ padding: '0px', display: 'flex', 'flex-direction': 'column', 'justify-content': 'center', 'align-items': 'center' }">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                      <!-- Add delete button here -->
 | 
			
		||||
                      <el-button type="danger"  icon="Delete" circle @click="removeGroupElement(groupIndex, positionIndex)" data-html2canvas-ignore="true"></el-button>
 | 
			
		||||
                      <el-button type="primary" icon="Plus"   circle @click="addGroupElement(groupIndex)" data-html2canvas-ignore="true"></el-button>
 | 
			
		||||
                      <img :src="position.avatar || '/assets/Shikigami/default.png'" class="image"
 | 
			
		||||
                           @click="editShikigami(groupIndex,positionIndex)"/>
 | 
			
		||||
                      <div>
 | 
			
		||||
                        <!-- Add delete button here -->
 | 
			
		||||
                        <el-button type="danger" icon="Delete" circle
 | 
			
		||||
                                   @click="removeGroupElement(groupIndex, positionIndex)"
 | 
			
		||||
                                   data-html2canvas-ignore="true"></el-button>
 | 
			
		||||
                        <el-button type="primary" icon="Plus" circle @click="addGroupElement(groupIndex)"
 | 
			
		||||
                                   data-html2canvas-ignore="true"></el-button>
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div class="avatar-wrapper">
 | 
			
		||||
                        <img :src="position.avatar || '/assets/Shikigami/default.png'"
 | 
			
		||||
                             class="avatar-image"
 | 
			
		||||
                             @click="editShikigami(groupIndex,positionIndex)"/>
 | 
			
		||||
                      </div>
 | 
			
		||||
                      <div style="padding: 14px; width: 95px">
 | 
			
		||||
 | 
			
		||||
                        <span>{{ position.name || "" }}</span>
 | 
			
		||||
                        <div class="bottom" data-html2canvas-ignore="true">
 | 
			
		||||
                          <el-button @click="editProperties(groupIndex,positionIndex)">配置属性</el-button>
 | 
			
		||||
                          <el-button @click="editProperty(groupIndex,positionIndex)">{{ t('editProperties') }}
 | 
			
		||||
                          </el-button>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <!--                        properties-->
 | 
			
		||||
                        <!--                        {"edit":true,"yuhun":{"yuhunSetEffect":[{"name":"狰","type":"attack","avatar":"/assets/Yuhun/狰.png"}],"target":"伤害输出","property2":["Attack"],"property4":["Attack"],"property6":["Crit","CritDamage"]},"levelRequired":"40","speed":"","skillRequiredMode":"all","skillRequired":["技能一","技能二","技能三"]}-->
 | 
			
		||||
                        <div v-if="position.properties">
 | 
			
		||||
                          <div>
 | 
			
		||||
                            <span style="display: inline-block; width: 100px; height: 25px; background-color: #666; border-top-left-radius: 5px; border-top-right-radius: 5px; margin-right: 5px; color: white; text-align: center; white-space: pre-wrap ">
 | 
			
		||||
                            <span
 | 
			
		||||
                                style="display: inline-block; width: 100px; height: 25px; background-color: #666; border-top-left-radius: 5px; border-top-right-radius: 5px; margin-right: 5px; color: white; text-align: center; white-space: pre-wrap ">
 | 
			
		||||
                              {{ position.properties.yuhun.yuhunSetEffect.map(item => item.name).join(' ') }}
 | 
			
		||||
                            </span>
 | 
			
		||||
                            <span style="display: inline-block; width: 100px; height: 25px; background-color: #666; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; margin-right: 5px; color: white; text-align: center; white-space: pre-wrap ">
 | 
			
		||||
                              {{ t('yuhun_target.' + position.properties.yuhun.target)}}·
 | 
			
		||||
                            <span
 | 
			
		||||
                                style="display: inline-block; width: 100px; height: 25px; background-color: #666; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; margin-right: 5px; color: white; text-align: center; white-space: pre-wrap ">
 | 
			
		||||
                              {{ t('yuhun_target.' + position.properties.yuhun.target) }}·
 | 
			
		||||
                            </span>
 | 
			
		||||
                          </div>
 | 
			
		||||
                          <div v-for="(value, key, index) in position.properties">
 | 
			
		||||
                          <div v-for="(value, key, index) in position.properties" data-html2canvas-ignore="true">
 | 
			
		||||
                            <span>{{ key }}</span> : <span>{{ value || '-' }}</span>
 | 
			
		||||
                          </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
@@ -68,7 +97,14 @@
 | 
			
		||||
 | 
			
		||||
          </div>
 | 
			
		||||
          <div>
 | 
			
		||||
            <QuillEditor v-model:content="content" contentType="html" theme="snow" :toolbar="toolbarOptions"/>
 | 
			
		||||
            <div data-html2canvas-ignore="true">
 | 
			
		||||
              <el-button type="primary" icon="CopyDocument" @click="copy(group.details)">{{ t('Copy') }}</el-button>
 | 
			
		||||
              <el-button type="primary" icon="Document" @click="paste(groupIndex,'details')">{{
 | 
			
		||||
                  t('Paste')
 | 
			
		||||
                }}
 | 
			
		||||
              </el-button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <QuillEditor v-model:content="group.details" contentType="html" theme="snow" :toolbar="toolbarOptions"/>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -84,15 +120,15 @@
 | 
			
		||||
    <!-- 现有的代码 -->
 | 
			
		||||
    <div style="margin: 20px" data-html2canvas-ignore="true">
 | 
			
		||||
      <!-- 触发截图的按钮 -->
 | 
			
		||||
      <button @click="prepareCapture">生成截图</button>
 | 
			
		||||
      <el-button type="primary" @click="prepareCapture">{{ t('prepareCapture') }}</el-button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 预览弹窗 -->
 | 
			
		||||
    <el-dialog id="preview-container" v-model="state.previewVisible" width="80%" :before-close="handleClose">
 | 
			
		||||
      <div style="max-height: 500px; overflow-y: auto;">
 | 
			
		||||
        <img v-if="state.previewImage" :src="state.previewImage" alt="Preview" style="width: 100%; display: block;" />
 | 
			
		||||
        <img v-if="state.previewImage" :src="state.previewImage" alt="Preview" style="width: 100%; display: block;"/>
 | 
			
		||||
      </div>
 | 
			
		||||
<!--      <img v-if="state.previewImage" :src="state.previewImage" alt="Preview" style="width: 100%; height: auto;" />-->
 | 
			
		||||
      <!--      <img v-if="state.previewImage" :src="state.previewImage" alt="Preview" style="width: 100%; height: auto;" />-->
 | 
			
		||||
      <span slot="footer" class="dialog-footer">
 | 
			
		||||
        <el-button @click="state.previewVisible = false">取 消</el-button>
 | 
			
		||||
        <el-button type="primary" @click="downloadImage">下 载</el-button>
 | 
			
		||||
@@ -103,13 +139,13 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref, reactive, toRefs } from 'vue';
 | 
			
		||||
import {ref, reactive, toRefs} from 'vue';
 | 
			
		||||
import draggable from 'vuedraggable';
 | 
			
		||||
import ShikigamiSelect from './ShikigamiSelect.vue';
 | 
			
		||||
import ShikigamiProperty from './ShikigamiProperty.vue';
 | 
			
		||||
import html2canvas from 'html2canvas';
 | 
			
		||||
import { useI18n } from 'vue-i18n'
 | 
			
		||||
import { QuillEditor } from '@vueup/vue-quill'
 | 
			
		||||
import {useI18n} from 'vue-i18n'
 | 
			
		||||
import {QuillEditor} from '@vueup/vue-quill'
 | 
			
		||||
import '@vueup/vue-quill/dist/vue-quill.snow.css' // 引入样式文件
 | 
			
		||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 | 
			
		||||
import shikigamiData from '../data/Shikigami.json';
 | 
			
		||||
@@ -120,8 +156,16 @@ const state = reactive({
 | 
			
		||||
  showSelectShikigami: false,
 | 
			
		||||
  showProperty: false,
 | 
			
		||||
  groups: [
 | 
			
		||||
    [{}, {}, {}, {}, {}],
 | 
			
		||||
    [{}, {}, {}, {}, {}]
 | 
			
		||||
    {
 | 
			
		||||
      shortDescription: '',
 | 
			
		||||
      groupInfo: [{}, {}, {}, {}, {}],
 | 
			
		||||
      details: ''
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      shortDescription: '',
 | 
			
		||||
      groupInfo: [{}, {}, {}, {}, {}],
 | 
			
		||||
      details: ''
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
  groupIndex: 0,
 | 
			
		||||
  positionIndex: 0,
 | 
			
		||||
@@ -130,31 +174,40 @@ const state = reactive({
 | 
			
		||||
  previewVisible: false, // 控制预览弹窗的显示状态
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const clipboard = ref('');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 获取当前的 i18n 实例
 | 
			
		||||
const { t } = useI18n()
 | 
			
		||||
// 初始化内容
 | 
			
		||||
const content = ref('<p>初始内容</p>')
 | 
			
		||||
const content1 = ref('<p>初始内容1</p>')
 | 
			
		||||
const {t} = useI18n()
 | 
			
		||||
 | 
			
		||||
const copy = (str) => {
 | 
			
		||||
  clipboard.value = str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const paste = (groupIndex, type) => {
 | 
			
		||||
  if ('shortDescription' == type)
 | 
			
		||||
    state.groups[groupIndex].shortDescription = clipboard.value
 | 
			
		||||
  else if ('details' == type)
 | 
			
		||||
    state.groups[groupIndex].details = clipboard.value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 定义工具栏选项
 | 
			
		||||
const toolbarOptions = [
 | 
			
		||||
 | 
			
		||||
  [{ 'color': [] }, { 'background': [] }],
 | 
			
		||||
  [{'color': []}, {'background': []}],
 | 
			
		||||
  ['bold', 'italic', 'underline', 'strike'],
 | 
			
		||||
  ['blockquote', 'code-block'],
 | 
			
		||||
  ['link', 'image', 'video', 'formula'],
 | 
			
		||||
  [{ 'header': 1 }, { 'header': 2 }],
 | 
			
		||||
  [{ 'list': 'ordered'}, { 'list': 'bullet' }, { 'list': 'check' }],
 | 
			
		||||
  [{ 'script': 'sub'}, { 'script': 'super' }],
 | 
			
		||||
  [{ 'indent': '-1'}, { 'indent': '+1' }],
 | 
			
		||||
  [{ 'direction': 'rtl' }],
 | 
			
		||||
  [{ 'size': ['small', false, 'large', 'huge'] }],
 | 
			
		||||
  [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
 | 
			
		||||
  [{ 'color': [] }, { 'background': [] }],
 | 
			
		||||
  [{ 'font': [] }],
 | 
			
		||||
  [{ 'align': [] }],
 | 
			
		||||
  ['clean']
 | 
			
		||||
  // ['blockquote', 'code-block'],
 | 
			
		||||
  // ['link', 'image', 'video', 'formula'],
 | 
			
		||||
  [{'header': 1}, {'header': 2}],
 | 
			
		||||
  [{'list': 'ordered'}, {'list': 'bullet'}, {'list': 'check'}],
 | 
			
		||||
  // [{ 'script': 'sub'}, { 'script': 'super' }],
 | 
			
		||||
  [{'indent': '-1'}, {'indent': '+1'}],
 | 
			
		||||
  // [{ 'size': ['small', false, 'large', 'huge'] }],
 | 
			
		||||
  // [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
 | 
			
		||||
  // [{ 'font': [] }],
 | 
			
		||||
  [{'align': []}],
 | 
			
		||||
  [{'direction': 'rtl'}],
 | 
			
		||||
  // ['clean']
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 定义方法
 | 
			
		||||
@@ -175,32 +228,32 @@ const updateShikigami = (shikigami) => {
 | 
			
		||||
  console.log("parent====> ", shikigami);
 | 
			
		||||
  state.showSelectShikigami = false;
 | 
			
		||||
 | 
			
		||||
  const oldProperties = state.groups[state.groupIndex][state.positionIndex].properties;
 | 
			
		||||
  state.groups[state.groupIndex][state.positionIndex] = shikigami;
 | 
			
		||||
  state.groups[state.groupIndex][state.positionIndex].properties = oldProperties;
 | 
			
		||||
  const oldProperties = state.groups[state.groupIndex].groupInfo[state.positionIndex].properties;
 | 
			
		||||
  state.groups[state.groupIndex].groupInfo[state.positionIndex] = shikigami;
 | 
			
		||||
  state.groups[state.groupIndex].groupInfo[state.positionIndex].properties = oldProperties;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const editProperties = (groupIndex, positionIndex) => {
 | 
			
		||||
const editProperty = (groupIndex, positionIndex) => {
 | 
			
		||||
  state.showProperty = true;
 | 
			
		||||
  state.groupIndex = groupIndex;
 | 
			
		||||
  state.positionIndex = positionIndex;
 | 
			
		||||
  state.currentShikigami = state.groups[groupIndex][positionIndex];
 | 
			
		||||
  state.currentShikigami = state.groups[groupIndex].groupInfo[positionIndex];
 | 
			
		||||
  console.log("currentShikigami", JSON.stringify(state.currentShikigami));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const closeProperty = () => {
 | 
			
		||||
  state.showProperty = false;
 | 
			
		||||
  state.currentShikigami = state.groups[state.groupIndex][state.positionIndex];
 | 
			
		||||
  state.currentShikigami = {};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const updateProperty = (property) => {
 | 
			
		||||
  state.showProperty = false;
 | 
			
		||||
  state.currentShikigami = {};
 | 
			
		||||
  state.groups[state.groupIndex][state.positionIndex].properties = property;
 | 
			
		||||
  state.groups[state.groupIndex].groupInfo[state.positionIndex].properties = property;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const removeGroupElement = (groupIndex, positionIndex) => {
 | 
			
		||||
  state.groups[groupIndex].splice(positionIndex, 1);
 | 
			
		||||
  state.groups[groupIndex].groupInfo.splice(positionIndex, 1);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const removeGroup = (groupIndex) => {
 | 
			
		||||
@@ -208,11 +261,15 @@ const removeGroup = (groupIndex) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addGroup = () => {
 | 
			
		||||
  state.groups.push([{}, {}, {}, {}, {}]);
 | 
			
		||||
  state.groups.push({
 | 
			
		||||
    shortDescription: '',
 | 
			
		||||
    groupInfo: [{}, {}, {}, {}, {}],
 | 
			
		||||
    details: ''
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addGroupElement = (groupIndex) => {
 | 
			
		||||
  state.groups[groupIndex].push({});
 | 
			
		||||
  state.groups[groupIndex].groupInfo.push({});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ignoreElements = (element) => {
 | 
			
		||||
@@ -231,10 +288,10 @@ const prepareCapture = async () => {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const canvas = await html2canvas(element,{
 | 
			
		||||
        ignoreElements:ignoreElements,
 | 
			
		||||
        height:element.scrollHeight
 | 
			
		||||
      }
 | 
			
		||||
    const canvas = await html2canvas(element, {
 | 
			
		||||
          ignoreElements: ignoreElements,
 | 
			
		||||
          height: element.scrollHeight
 | 
			
		||||
        }
 | 
			
		||||
    );
 | 
			
		||||
    state.previewImage = canvas.toDataURL();
 | 
			
		||||
    if (!state.previewImage) {
 | 
			
		||||
@@ -275,4 +332,27 @@ const handleClose = (done) => {
 | 
			
		||||
.ql-toolbar {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 正方形容器 */
 | 
			
		||||
.avatar-wrapper {
 | 
			
		||||
  width: 100px;         /* 正方形边长 */
 | 
			
		||||
  height: 100px;        /* 与宽度相同 */
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;     /* 隐藏超出部分 */
 | 
			
		||||
  border-radius: 50%;   /* 圆形裁剪 */
 | 
			
		||||
  //border: 2px solid #fff; /* 可选:添加边框 */
 | 
			
		||||
  box-shadow: 0 2px 8px rgba(0,0,0,0.1); /* 可选:添加阴影 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 图片样式 */
 | 
			
		||||
.avatar-image {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  object-fit: cover;    /* 关键属性:保持比例填充容器 */
 | 
			
		||||
  object-position: center; /* 居中显示 */
 | 
			
		||||
  display: block;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "Copy": "复制",
 | 
			
		||||
  "Paste": "粘贴",
 | 
			
		||||
  "editProperties": "配置属性",
 | 
			
		||||
  "prepareCapture": "生成截图",
 | 
			
		||||
  "yuhun_target": {
 | 
			
		||||
    "1": "伤害",
 | 
			
		||||
    "2": "命中",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user