Compare commits

...

2 Commits

Author SHA1 Message Date
soul2 057fcdf401 更新 2 years ago
soul2 bc96eaa91a 新增war3技能文本生成 2 years ago
  1. 6
      .env.development
  2. 7
      package.json
  3. 2
      src/layout/index.vue
  4. 7
      src/main.js
  5. 10
      src/router/index.js
  6. 8
      src/style/element-ui.scss
  7. 3
      src/style/index.scss
  8. 1
      src/style/transition.scss
  9. 16
      src/utils/ArrayUtils.js
  10. 83
      src/utils/StringUtils.js
  11. 201
      src/utils/storageHelper.ts
  12. 195
      src/utils/tools.js
  13. 4
      src/views/home/index.vue
  14. 4
      src/views/sodemo/index.vue
  15. 3
      src/views/soui/index.vue
  16. 272
      src/views/wc3word/color.vue
  17. 184
      src/views/wc3word/dialog/SpellBuilder.vue
  18. 108
      src/views/wc3word/dialog/load.vue
  19. 26
      src/views/wc3word/dialog/version.js
  20. 286
      src/views/wc3word/edit.vue
  21. 72
      src/views/wc3word/index.vue
  22. 127
      src/views/wc3word/spell.vue
  23. 55
      src/views/wc3word/updateRecord.vue
  24. 8
      src/views/word_builder/tools/tools.js
  25. 153
      src/views/word_builder/wc3data/json.js
  26. 2
      src/views/word_builder/wc3data/temp.js

@ -5,3 +5,9 @@ VUE_APP_CONTEXT_PATH = '/'
# 接口地址 # 接口地址
VUE_APP_BASE_API = 'http://localhost:7330' VUE_APP_BASE_API = 'http://localhost:7330'
# 测试运行的端口
port = '6830'
# 测试运行的端口
port = '6830'

@ -3,7 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "dev": "vue-cli-service serve",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
@ -12,11 +12,12 @@
"core-js": "^3.6.5", "core-js": "^3.6.5",
"element-ui": "^2.15.6", "element-ui": "^2.15.6",
"js-cookie": "^2.2.0", "js-cookie": "^2.2.0",
"nprogress": "^0.2.0",
"sass-loader": "^10.0.5",
"node-sass": "^7.0.3", "node-sass": "^7.0.3",
"normalize.css": "7.0.0", "normalize.css": "7.0.0",
"nprogress": "^0.2.0",
"sass-loader": "^10.0.5",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-cookies": "^1.8.3",
"vue-router": "^3.5.2", "vue-router": "^3.5.2",
"vuex": "^3.6.2" "vuex": "^3.6.2"
}, },

@ -5,7 +5,7 @@
<el-header> <el-header>
<navbar/> <navbar/>
</el-header> </el-header>
<el-main> <el-main style="padding: 0;">
<el-scrollbar> <el-scrollbar>
<app-main/> <app-main/>
</el-scrollbar> </el-scrollbar>

@ -3,10 +3,17 @@ import App from './App.vue'
import store from "@/store"; import store from "@/store";
import ElementUI from 'element-ui' import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css' import 'element-ui/lib/theme-chalk/index.css'
import 'element-ui/lib/theme-chalk/base.css';
import router from './router' import router from './router'
import '@/style/index.scss' // 全局样式 import '@/style/index.scss' // 全局样式
import '@/router/beforce' import '@/router/beforce'
import '@/utils/StringUtils'
import '@/utils/ArrayUtils'
import VueCookies from 'vue-cookies'
Vue.config.productionTip = false
Vue.use(VueCookies)
Vue.use(ElementUI) Vue.use(ElementUI)
new Vue({ new Vue({

@ -35,6 +35,16 @@ export const routes = [
meta: {title: '灵魂演示', icon: 'dashboard'} meta: {title: '灵魂演示', icon: 'dashboard'}
}] }]
}, },
{
path: '',
component: Layout,
children: [{
path: '/wc3/word',
name: 'Word',
component: () => import('@/views/wc3word/index'),
meta: {title: '文本生成', icon: 'dashboard'}
}]
},
// { // {
// path: '', // path: '',
// component: Layout, // component: Layout,

@ -0,0 +1,8 @@
// to fixed https://github.com/ElemeFE/element/issues/2461
.el-dialog {
transform: none;
left: 0;
position: relative;
margin: 0 auto;
}

@ -1,4 +1,5 @@
@import "./transition.scss"; @import "transition";
@import "element-ui";
* { * {
margin: 0; margin: 0;

@ -46,3 +46,4 @@
.breadcrumb-leave-active { .breadcrumb-leave-active {
position: absolute; position: absolute;
} }

@ -0,0 +1,16 @@
/**
* 求出多个数组的最小长度
* @returns {*|number}
*/
Array.prototype.minFor = function () {
return this.reduce((min, arr) => Math.min(min, arr.length), Infinity);
}
/**
* 让每个子数组只保留前n个元素
* @param n
* @returns {*[]}
*/
Array.prototype.startCut = function (n) {
return this.map(arr => arr.slice(0, n));
}

@ -0,0 +1,83 @@
/**
* 调用示例
*
* var template1="我是{0},今年{1}了";
* var template2="我是{name},今年{age}了";
* var result1=template1.format("loogn",22);
* var result2=template1.format({name:"loogn",age:22});
*/
String.prototype.format = function (args) {
if (arguments.length > 0) {
var result = this;
if (arguments.length == 1 && typeof (args) == "object") {
for (var key in args) {
var reg = new RegExp("({" + key + "})", "g");
result = result.replace(reg, args[key]);
}
} else {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] == undefined) {
return "";
} else {
var reg = new RegExp("({[" + i + "]})", "g");
result = result.replace(reg, arguments[i]);
}
}
}
return result;
} else {
return this;
}
}
// chatGPT的 2.0 改进建议
// String.prototype.format = function (...args) {
// const pattern = /\{(\d*|\w*)\}/g;
// return this.replace(pattern, (match, p1) => {
// if (p1 === '') {
// throw new Error('占位符不能为空');
// }
//
// if (isNaN(p1)) {
// if (!args[0] || typeof args[0] !== 'object') {
// throw new Error('需要传入一个对象作为参数');
// }
//
// const value = args[0][p1];
// if (value === undefined) {
// throw new Error(`对象中没有名为${p1}的属性`);
// }
//
// return value;
// }
//
// const index = parseInt(p1);
// if (index >= args.length) {
// throw new Error(`占位符{${p1}}没有对应的参数`);
// }
//
// return args[index];
// });
// };
/**
* 取出所有a到b中间的字符串
*
* @param a
* @param b
*/
String.prototype.between = function (a, b) {
if (arguments.length > 0) {
var results = [];
var reg = new RegExp(`\\${a}([^\\${b}]+)\\${b}`, "g");
var match;
while ((match = reg.exec(this)) !== null) {
results.push(match[1]);
}
return results;
} else {
return this.between("{", "}");
}
}

@ -0,0 +1,201 @@
/**
* chatGPT改进版
*/
interface StorageItem {
value: any;
lostTime?: Date;
}
const storageHelper = {
/**
*
* @param name
* @param key key
* @param value
* @param time
*/
set: function (name: string, key: string, value: any, time?: Date): void {
const str = localStorage.getItem(name);
let storage: { [key: string]: StorageItem };
try {
storage = JSON.parse(str || '{}')
} catch (e) {
console.error(`无法解析数据名称 "${name}" ,该数据可能已损坏。`)
console.error('目标数据:\n' + str)
return;
}
storage[key] = {
value,
lostTime: time,
}
localStorage.setItem(name, JSON.stringify(storage))
},
/**
*
* @param name
* @param key
*/
get: function (name: string, key: string): any {
const str = localStorage.getItem(name);
let storage: { [key: string]: StorageItem };
try {
storage = JSON.parse(str)
} catch (e) {
console.error(`无法解析数据名称 "${name}" ,该数据可能已损坏。`)
console.error('目标数据:\n' + str)
return;
}
this.clearLostTimeData(name)
return storage[key]?.value;
},
/**
*
* @param name
* @param key
*/
remove: function (name: string, key?: string | string[]) {
if (!name) return;
const str = localStorage.getItem(name);
let storage: { [key: string]: StorageItem };
try {
storage = JSON.parse(str || '{}')
} catch (e) {
console.error(`无法解析数据名称 "${name}" ,该数据可能已损坏。`)
console.error('目标数据:\n' + str)
return;
}
if (!key) {
localStorage.removeItem(name);
return;
}
const keys = Array.isArray(key) ? key : [key];
for (const k of keys) {
if (storage[k]) {
storage[k] = undefined;
}
}
localStorage.setItem(name, JSON.stringify(storage));
},
/**
*
* @param name
*/
clearLostTimeData: function (name: string): boolean {
const str = localStorage.getItem(name);
let storage: { [key: string]: StorageItem };
try {
storage = JSON.parse(str || '{}');
} catch (e) {
return false;
}
const keys = Object.keys(storage);
const now = new Date().getTime();
let changed = false;
for (const k of keys) {
if (storage[k].lostTime && storage[k].lostTime.getTime() < now) {
storage[k] = undefined;
changed = true;
}
}
if (changed) {
const remainingKeys = Object.keys(storage).filter(k => storage[k]);
if (remainingKeys.length > 0) {
localStorage.setItem(name, JSON.stringify(storage));
} else {
localStorage.removeItem(name);
}
}
return changed;
},
};
export default storageHelper;
/**
*
*/
// const storageHelper = {
// /**
// *
// * @param name 保存名称
// * @param key 保存的key
// * @param value 保存的值
// * @param time 失活时间,默认无限
// */
// set: function (name: string, key: string, value: any, time: Date = undefined) {
// const str = localStorage.getItem(name);
// let storage: object;
// try {
// storage = JSON.parse(str || '{}')
// } catch (e) {
// console.error(`无法解析数据名称 "${name}" ,该数据可能已损坏。`)
// console.error('目标数据:\n' + str)
// return;
// }
// storage[key] = {
// value,
// lostTime: time,
// }
// localStorage.setItem(name, JSON.stringify(storage))
// },
// get: function (name: string, key: string): any {
// const str = localStorage.getItem(name);
// let storage: object;
// try {
// storage = JSON.parse(str)
// } catch (e) {
// console.error(`无法解析数据名称 "${name}" ,该数据可能已损坏。`)
// console.error('目标数据:\n' + str)
// return;
// }
// this.clearLostTimeData(name)
// return storage[key].data
// },
// remove: function (name: string, key: any) {
// if (name) {
// if (key) {
// const str = localStorage.getItem(name);
// let storage: object;
// try {
// storage = JSON.parse(str)
// } catch (e) {
// console.error(`无法解析数据名称 "${name}" ,该数据可能已损坏。`)
// console.error('目标数据:\n' + str)
// return;
// }
// if (Array.isArray(key)) {
//
// }
// } else {
// localStorage.removeItem(name)
// }
// }
// },
// clearLostTimeData: function (name: string) {
// const str = localStorage.getItem(name);
// let storage: object;
// try {
// storage = JSON.parse(str);
// } catch (e) {
// return false;
// }
// let keys = Object.keys(storage)
// let now = new Date().getTime()
// keys.forEach((key, i) => {
// if (storage[key].lostTime && storage[key].lostTime.getTime() < now) {
// storage[key] = undefined
// }
// })
// keys = Object.keys(storage)
// if (keys.length == 0) {
// localStorage.removeItem(name)
// return false;
// } else {
// return true;
// }
// },
// }
//
// export default storageHelper

@ -0,0 +1,195 @@
export const defaultColorConfig = {
learnLevel: '#33ccff',
property: '#33cc33',
hotKey: '#ffcc00',
level: '#33ccff',
learnUpdateLevel: '#ff9900',
nature: '#ffcccc'
}
export function createObjs(len, fn) {
let arr = [];
for (let i = 0; i < len; i++) {
let res = fn(i)
arr.push(res)
}
return arr
}
export function formula2arr(str, keys = 'abcdefghijklmnopqrstuvwxyz'.split('')) {
// 解析数量
let formulas = str.split(';');
const num = parseInt(formulas[0])
// 解析参数
formulas = formulas[1].split('/');
// 构建返回
const result = [];
// 解析公式
formulas = formulas.map((f) => {
let formula = f.split("+")
formula = formula.map(e => parseInt(e))
return {
base: formula[0],
plus: formula[1]
}
})
// 生成对象
for (let i = 0; i < num; i++) {
let obj = {}
for (let j = 0; j < formulas.length; j++) {
let key = keys[j]
obj[key] = formulas[j].base + formulas[j].plus * i
}
result.push(obj)
}
return result;
}
function toCfg(s, c) {
if (typeof s !== 'string') {
return c
}
let items = s.split(", ")
let cfg = c
if (items.length > 0) {
items.forEach((e) => {
let p = e.split(":")
cfg[p[0]] = p[1]
})
}
return cfg
}
/**
* [xxx]的形式分析数据自定义配置使用{}在参数str内附带没有指定自定义配置时会使用默认配置
* [a=2/3/4][b=16+8][lv=3]{ls:/, fs:,}
* warning: 自定义配置以 为分隔符空格不可省略
*
* @param str
* @param cfg <ul>配置:
* <li>fs公式数据的分隔符</li>
* <li>ls数值列表的分隔符</li>
* <li>es属性的分隔符</li>
* <li>lv等级的属性名</li>
* </ul>
* @returns {*[]}
*/
export function conversion(str, cfg = {fs: "+", ls: ",", es: "=", lv: "lv"}) {
// 加载自定义配置
cfg = toCfg(str.between()[0], cfg)
// 过滤无效信息
const pairs = checkValid((str).between("[", "]"))
// 判断必备条件,否则返回空数组
if (str.indexOf("[" + cfg.lv + cfg.es) === -1 || isNaN(parseInt((str).between("[" + cfg.lv + cfg.es, "]")))) {
return []
}
const lv = parseInt((str).between("[" + cfg.lv + cfg.es, "]"))
let items = {}
let itemKeys = []
const result = []
pairs.forEach(pair => {
let p = pair.split(cfg.es)
itemKeys.push(p[0])
if (p[1].indexOf(cfg.fs) !== -1) { // 有+号,是公式
let fps = p[1].split(cfg.fs)
let rules = {base: parseFloat(fps[0]), plus: parseFloat(fps[1])}
items[p[0]] = createObjs(lv, i => rules.base + rules.plus * i)
} else { // 没有+号,是数值list
items[p[0]] = arrCut(p[1].split(cfg.ls).filter(e => !isNaN(parseFloat(e))).map(e => parseFloat(e)), lv)
}
})
for (let i = 0; i < lv; i++) {
let obj = {}
itemKeys.forEach((k, n) => {
obj[k] = items[k][i]
})
result.push(obj)
}
return result
}
/**
* 检查输入的内容是否为a=b的形式并返回合格的内容
* a的通过规则为a-z的其中一个
* b可以是任意字符串
*
* @param arr
* @returns {*[]}
*/
export function checkValid(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
const str = arr[i];
const regex = /^[a-z]=[^\s]+$/;
if (regex.test(str)) {
result.push(str);
}
}
return result;
}
export function copyToClipboard(text) {
const textarea = document.createElement('textarea'); // 创建一个文本域元素
textarea.value = text; // 将传入的文本内容赋值给文本域
textarea.setAttribute('readonly', ''); // 设置文本域只读
textarea.style.position = 'absolute';
textarea.style.left = '-9999px'; // 将文本域定位到屏幕外
document.body.appendChild(textarea); // 将文本域添加到页面上
textarea.select(); // 选中文本域中的内容
document.execCommand('copy'); // 将选中的内容复制到系统剪切板
document.body.removeChild(textarea); // 移除文本域
}
/**
* 如果a的长度超过b就返回a的前b项
* 如果小于则添加字符串"null"使a的长度到达b
* 如果相等则直接返回a
*
* @param arr
* @param targetLength
* @returns {*}
*/
function arrCut(arr, targetLength) {
if (arr.length > targetLength) {
return arr.slice(0, targetLength);
} else if (arr.length < targetLength) {
let nulls = new Array(targetLength - arr.length).fill("null");
return arr.concat(nulls);
} else {
return arr;
}
}
/**
* 中文标点符号换成英文标点符号以赋予输入中文符号不出错的能力
*
* @param str
* @returns {*}
* @constructor
*/
export function symbolCn2En(str) {
if (Array.isArray(str)) {
return str.map(s => symbolCn2En(s));
}
const map = {
',': ',',
'。': '.',
'?': '?',
'!': '!',
':': ':',
';': ';',
'“': '"',
'”': '"',
'‘': "'",
'’': "'",
'(': '(',
')': ')',
'【': '[',
'】': ']',
'《': '<',
'》': '>',
'、': ','
};
return str.replaceAll(/[\u4e00-\u9fa5]/g, c => map[c] || c);
}

@ -123,6 +123,10 @@ export default {
</script> </script>
<style scoped> <style scoped>
#home {
padding-top: 20px;
}
#dl-btn .el-button { #dl-btn .el-button {
margin-top: 7px; margin-top: 7px;
} }

@ -110,6 +110,10 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
#so-demo {
padding-top: 20px;
}
#goto-btn .el-button { #goto-btn .el-button {
margin-top: 7px; margin-top: 7px;
} }

@ -63,4 +63,7 @@ export default {
</script> </script>
<style scoped> <style scoped>
#soui {
padding-top: 20px;
}
</style> </style>

@ -0,0 +1,272 @@
<template>
<div class="app-container">
<el-form ref="form" :model="colorConfig" label-width="110px">
<el-col :span="11" class="example-box">
<spell
v-if="e.name === exampleSpell"
v-for="(e,i) in exampleSpellList"
:spell-data="e"
:color-config="colorConfig"
:module="effectExample"
/>
</el-col>
<el-col :span="12" :offset="1" class="example-setting">
<el-row style="text-align:left;">
<el-divider content-position="left">示例设置</el-divider>
<p>
<el-radio-group v-model="effectExample" size="mini">
<el-radio-button label="学习"></el-radio-button>
<el-radio-button label="普通"></el-radio-button>
</el-radio-group>
</p>
<p>
<el-radio-group v-model="exampleSpell" size="mini" @change="handleExampleChange">
<el-radio-button v-for="(e,i) in exampleSpellList" :label="e.name"></el-radio-button>
</el-radio-group>
</p>
<p>
<el-radio-group v-model="exampleLevel" size="mini" @change="handleExampleLevelChange">
<el-radio-button
v-for="(e,i) in exampleLevelList"
:label="(i+1)"
>{{ (1 + i) + '级' }}
</el-radio-button>
</el-radio-group>
</p>
</el-row>
<el-row style="margin-top: 15px;">
<el-form-item label="热键:" style="margin-bottom: 0;">
<el-col :span="5">
<el-color-picker size="mini" v-model="colorConfig.hotKey"/>
</el-col>
<el-col :span="7">{{ colorConfig.hotKey }}</el-col>
</el-form-item>
<el-form-item label="学习等级:" style="margin-bottom: 0;">
<el-col :span="5">
<el-color-picker size="mini" v-model="colorConfig.learnLevel"/>
</el-col>
<el-col :span="7">{{ colorConfig.learnLevel }}</el-col>
</el-form-item>
<el-form-item label="技能属性:" style="margin-bottom: 0;">
<el-col :span="5">
<el-color-picker size="mini" v-model="colorConfig.property"/>
</el-col>
<el-col :span="7">{{ colorConfig.property }}</el-col>
</el-form-item>
<el-form-item label="升级等级前缀:" style="margin-bottom: 0;">
<el-col :span="5">
<el-color-picker size="mini" v-model="colorConfig.learnUpdateLevel"/>
</el-col>
<el-col :span="7">{{ colorConfig.learnUpdateLevel }}</el-col>
</el-form-item>
<el-form-item label="特殊描述:" style="margin-bottom: 0;">
<el-col :span="5">
<el-color-picker size="mini" v-model="colorConfig.nature"/>
</el-col>
<el-col :span="7">{{ colorConfig.nature }}</el-col>
</el-form-item>
<div style="text-align:right;margin-top: 15px;margin-bottom: 15px;">
<el-button size="mini" type="primary" plain @click="resetColorConfig">恢复默认</el-button>
<el-button size="mini" type="success" plain @click="saveColorConfig">保存</el-button>
<el-button size="mini" type="warning" plain @click="loadColorConfig">读取</el-button>
<el-button size="mini" type="danger" plain @click="removeColorConfig">删除</el-button>
</div>
</el-row>
</el-col>
</el-form>
</div>
</template>
<script>
import Spell from "@/views/wc3word/spell";
import {createObjs, defaultColorConfig} from "@/utils/tools";
export default {
name: 'Color',
props: {
colorDefaultConfig: Object
},
components: {Spell, defaultColorConfig},
data() {
return {
colorCfg: {},
exampleSpell: null,
exampleLevel: 1,
effectExample: '学习',
exampleSpellList: [
{
id: "Ahtb",
lv: "1",
name: "风暴之锤",
hotKey: "T",
effect: "向目标投掷一巨大的魔法锤,对其造成一定伤害并使其陷入眩晕。",
pros: [
{name: '法力消耗', val: '75'},
{name: '施法距离', val: '800'},
{name: '冷却时间', val: '6'},
],
updateWord: {
text: "{d}点伤害,{t}秒的晕眩时间",
vals: createObjs(5, i => ({d: 100 + i * 110, t: 3 + i}))
},
nature: "",
normalWord: {
text: '向目标投掷一巨大的魔法锤,对其造成{d}点伤害并使其{t}秒内处于眩晕状态。',
vals: createObjs(5, i => ({d: 100 + i * 110, t: 3 + i}))
}
},
{
id: "Ahbz",
lv: "1",
name: "暴风雪",
hotKey: "F",
effect: "能召唤出若干次冰片攻击,对目标区域内的单位造成一定的伤害。",
pros: [
{name: '法力消耗', val: '75'},
{name: '施法距离', val: '600'},
{name: '冷却时间', val: '9'},
],
updateWord: {
text: "召唤{c}次,每次{d}点伤害。",
vals: createObjs(6, i => ({c: i * 2 + 6, d: i * 10 + 30}))
},
nature: "需要持续施法",
normalWord: {
text: '召唤出{c}次的冰片攻击,每一次攻击能对一小块区域内的单位造成{d}的伤害值。',
vals: createObjs(6, i => ({c: i * 2 + 6, d: i * 10 + 30}))
}
},
],
}
},
computed: {
exampleLevelList() {
return this.exampleSpellList.filter(e => e.name === this.exampleSpell)[0].updateWord.vals.length
},
colorConfig() {
return this.colorCfg
}
},
watch: {
colorCfg() {
this.$emit("updateCfg", this.colorCfg)
}
},
created() {
this.colorCfg = Object.assign({}, this.colorDefaultConfig)
this.exampleSpell = this.exampleSpellList[0].name
},
mounted() {
},
methods: {
saveColorConfig() {
// console.log('saving')
let colorConfigList = JSON.parse(localStorage.getItem('color-config-list') || '[]')
let colorCfgNames = colorConfigList.map(e => e.name)
this.$prompt('取个名字吧!\n会覆盖同名的方案。', '提示', {
confirmButtonText: '确定',
// cancelButtonText: '',
showCancelButton: false,
showClose: false,
}).then(({value}) => {
let index = colorCfgNames.indexOf(value)
if (index === -1) {
colorConfigList.push({name: value, cfg: this.colorConfig})
} else {
colorConfigList[index].cfg = this.colorConfig
}
localStorage.setItem('color-config-list', JSON.stringify(colorConfigList))
this.$message({type: 'success', message: '保存成功!'});
}).catch(() => {
});
},
loadColorConfig() {
let colorConfigList = JSON.parse(localStorage.getItem('color-config-list') || '[]')
if (colorConfigList.length > 0) {
let colorCfgNames = colorConfigList.map(e => e.name)
this.$prompt('你要读取哪个方案?\n已保存方案:\n' + colorCfgNames, '提示', {
confirmButtonText: '确定',
// cancelButtonText: '',
showCancelButton: false,
showClose: false,
}).then(({value}) => {
let index = colorCfgNames.indexOf(value)
if (index === -1) {
this.$message({type: 'error', message: '方案不存在!'});
} else {
this.colorConfig = colorConfigList[index].cfg
this.$message({type: 'success', message: '读取成功!'});
}
}).catch(() => {
});
} else {
this.$message({type: 'error', message: '没有已保存的方案!'});
}
},
removeColorConfig() {
let colorConfigList = JSON.parse(localStorage.getItem('color-config-list') || '[]')
if (colorConfigList.length > 0) {
let colorCfgNames = colorConfigList.map(e => e.name)
this.$prompt('你要删除哪个方案?\n已保存方案的名称有:\n' + colorCfgNames,
'提示', {
confirmButtonText: '确定',
// cancelButtonText: '',
showCancelButton: false,
showClose: false,
}).then(({value}) => {
let index = colorCfgNames.indexOf(value)
if (index === -1) {
this.$message({type: 'error', message: '方案不存在!'});
} else {
colorConfigList = colorConfigList.filter(e => e !== colorConfigList[index])
localStorage.setItem('color-config-list', JSON.stringify(colorConfigList))
this.$message({type: 'success', message: '操作成功!'});
}
}).catch(() => {
});
} else {
this.$message({type: 'error', message: '没有已保存的方案!'});
}
},
resetColorConfig() {
// console.log('reset')
this.colorCfg = Object.assign({}, defaultColorConfig)
},
handleExampleChange() {
this.exampleSpellList.map(e => e.lv = 1)
this.exampleLevel = 1
},
handleExampleLevelChange() {
this.exampleSpellList.map(e => e.lv = this.exampleLevel)
}
}
}
</script>
<style scoped lang="scss">
.example-setting el-form-item {
el-color-picker {
min-width: 80px;
}
margin-bottom: 0;
}
.example-setting p {
margin-top: 15px;
}
.example-box {
max-height: 40vh;
}
.example-box p {
font-size: 12px !important;
font-weight: bold !important;
overflow-y: auto;
max-height: 30vh;
}
</style>

@ -0,0 +1,184 @@
<template>
<el-dialog ref="dialog" width="50%" :title="title" :visible.sync="visible" @close="closeDialog"
:append-to-body="true" :show-close="false" :transition="dialogTransition">
<div class="builder-dialog">
<el-col :span="12" style="padding-right: 20px;">
<el-divider content-position="center">结果展示</el-divider>
<spell :spell-data="spell" :module="spellModule" :color-config="color"/>
</el-col>
<el-col :span="11" :offset="1" class="cp-rect">
<el-divider content-position="left">结果展示设置</el-divider>
<el-radio-group v-model="spellModule" size="mini">
<el-radio-button label="学习"></el-radio-button>
<el-radio-button label="普通"></el-radio-button>
</el-radio-group>
<el-row class="cp-item">
<el-radio-group v-model="spellData.lv" size="mini">
<el-radio-button
v-for="(e,i) in exampleLevelList"
:label="(i+1)"
>{{ (1 + i) + '级' }}
</el-radio-button>
</el-radio-group>
</el-row>
<el-row class="cp-item">
<el-divider content-position="left">点击复制</el-divider>
<el-button-group>
<el-button type="success" plain size="mini"
@click="handleBuilder('title')">学习标题
</el-button>
<el-button type="success" plain size="mini"
@click="handleBuilder('export')">学习扩展
</el-button>
</el-button-group>
</el-row>
<el-row class="cp-item" v-for="(e,i) in spell.updateWord.vals">
<el-button-group>
<el-button :type="i%2===1?'success':'primary'" plain size="mini"
@click="handleBuilder('title', (i+1))">
{{ (i + 1) }}级标题
</el-button>
<el-button :type="i%2===1?'success':'primary'" plain size="mini"
@click="handleBuilder('export', (i+1))">
{{ (i + 1) }}级扩展
</el-button>
</el-button-group>
</el-row>
</el-col>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="visible = false" size="mini">关闭</el-button>
</div>
</el-dialog>
</template>
<script>
import Spell from "@/views/wc3word/spell";
import {copyToClipboard} from "@/utils/tools";
export default {
name: 'SpellBuilderDialog',
props: {
spellData: {
type: Object,
default: () => false
},
colorConfig: Object,
show: {
type: Boolean,
default: () => false
}
},
components: {Spell},
data() {
return {
visible: this.show,
spellModule: '学习',
dialogTransition: 'dialog-fade'
}
},
computed: {
spell() {
return this.spellData
},
exampleLevelList() {
return this.spellData.updateWord.vals.length || 1
},
color() {
return this.colorConfig
},
title() {
return '技能文本生成结果'
}
},
watch: {
visible() {
this.$emit('update:show', false)
}
},
created() {
},
mounted() {
},
methods: {
closeDialog() {
//
},
handleSave() {
},
dyeing(str, color) {
const prefix = '|cff'
const suffix = '|r'
return color ? (prefix + color.replace('#', "") + str + suffix) : str
},
handleBuilder(module, lv) {
const {learnLevel, property, hotKey, level, learnUpdateLevel, nature} = this.color
const sp = this.spell
let result = ''
if (!lv) {
// lv
lv = '%d'
if (module === 'title') {
result = `学习 ${this.dyeing(lv + ' 级', learnLevel)} ${sp.name}(${this.dyeing(sp.hotKey, hotKey)})`
} else if (module === 'export') {
result += sp.effect + '\n'
result += sp.natual ? (sp.natual + '\n') : ''
sp.pros.forEach(e => {
result += `\n${this.dyeing(e.name, property)}${e.val}`
})
if (sp.updateWord.text && sp.updateWord.vals) {
result += "\n"
sp.updateWord.vals.forEach((v, i) => {
let w = sp.updateWord.text.format(v)
w = w.endsWith("。") ? w : w + "。"
result += `\n${this.dyeing((i + 1) + '级', learnUpdateLevel)} - ${w}`
})
}
}
} else {
// lv
if (module === 'title') {
result = `${sp.name}(${this.dyeing(sp.hotKey, hotKey)}) - [${this.dyeing(lv + ' 级', learnLevel)}]`
} else if (module === 'export') {
let n = sp.normalWord
let ps = sp.pros.filter(e => e.name !== '法力消耗')
result += n.text.format(n.vals[lv - 1])
result += sp.natual ? (sp.natual + '\n') : ''
if (ps && ps.length > 0) {
result += '\n'
ps.forEach(p => {
result += `\n${this.dyeing(p.name, property)}${p.val}`
})
}
}
}
// console.log('result -> ', result)
// return result
copyToClipboard(result)
const h = this.$createElement;
this.$notify({
title: '来自Soul2的提示',
message: h('span', {style: 'color: teal'}, '生成的文本已输出到剪切板。'),
position: 'bottom-right',
duration: 3000,
// showClose: false
});
}
}
}
</script>
<style scoped lang="scss">
.builder-dialog {
overflow-y: auto;
min-height: 35vh;
padding-left: 5%;
padding-right: 5%;
.cp-rect .cp-item {
margin-top: 8px;
margin-bottom: 8px;
}
}
</style>

@ -0,0 +1,108 @@
<template>
<el-dialog ref="dialogForm" width="30%" :title="title" :visible.sync="visible" @close="closeDialog"
:append-to-body="true">
<div style="padding-left: 10%;padding-right: 10%;">
<el-radio-group v-model="checked" size="mini">
<el-radio v-for="(e,i) in spellLoadList" :label="e" border>
{{ e !== spellMap[e].name ? e + `<${spellMap[e].name}>` : e }}
</el-radio>
</el-radio-group>
</div>
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="visible = false">取消</el-button>
<el-button size="mini" type="primary" @click="handleLoad">读取</el-button>
<el-button size="mini" type="warning" @click="handleRemove">删除</el-button>
<el-button size="mini" type="danger" @click="handleRemoveAll">删除全部</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'LoadSpellDialog',
props: {
spellMap: {
type: Object,
require: true
},
spellList: {
type: Array
},
show: {
type: Boolean,
default: () => false
}
},
components: {},
data() {
return {
visible: this.show,
checked: null
}
},
computed: {
title() {
return '你要读取哪个'
},
spellLoadList() {
return this.spellList || Object.keys(this.spellMap)
},
},
watch: {
visible() {
this.$emit('update:show', false)
}
},
created() {
},
mounted() {
},
methods: {
closeDialog() {
//
},
handleLoad() {
if (this.checked) {
this.$emit('load', this.spellMap[this.checked])
// console.log('checked -> ', this.checked)
this.visible = false
} else {
this.$message({type: 'info', message: '你还没选择!'});
}
},
handleRemove() {
if (this.checked) {
this.$confirm('此操作将永久删除这个记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$emit('remove', this.checked)
// console.log('checked -> ', this.checked)
this.visible = false
}).catch(() => {
})
} else {
this.$message({type: 'info', message: '你还没选择!'});
}
},
handleRemoveAll() {
this.$confirm('此操作将永久删除所有保存记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'danger'
}).then(() => {
localStorage.removeItem('spell-list')
this.$message({type: 'success', message: '记录已清空!'});
this.visible = false
}).catch(() => {
})
},
}
}
</script>
<style scoped lang="scss">
</style>

@ -0,0 +1,26 @@
const version = {
'1.0': {
7: [
{type: '完成', value: '更新日志'},
{type: '修复', value: '技能文本恢复默认时没有清空数值的bug'},
],
6: [
{type: '新', value: '导出导入技能'},
],
5: [
{type: '完成', value: '技能文本的保存能力'},
{type: '修复', value: '新的技能数值输入方法'},
],
3: [
{type: '完成', value: '生成器文本实时同步'},
{type: '完成', value: '色彩及生成器恢复默认按钮'},
{type: '完成', value: '保存色彩方案'},
],
2: [
{type: '完成', value: '色彩'},
{type: '完成', value: '编辑'},
],
}
}
export default version

@ -0,0 +1,286 @@
<template>
<div class="edit-container">
<el-col :span="9" style="padding-top: 2vh;text-align:left;">
<el-row class="spell-info-setting">
<el-radio-group v-model="spellInfo.module" size="mini">
<el-radio-button label="学习"></el-radio-button>
<el-radio-button label="普通"></el-radio-button>
</el-radio-group>
</el-row>
<el-row class="spell-info-setting">
<el-radio-group v-model="spellData.lv" size="mini">
<el-radio-button
v-for="(e,i) in exampleLevelList"
:label="(i+1)"
>{{ (1 + i) + '级' }}
</el-radio-button>
</el-radio-group>
</el-row>
<el-row class="spell-info-setting">
<el-button size="mini" type="success" plain @click="handleBuilder">生成</el-button>
<el-button size="mini" type="primary" plain @click="handleResetSpellData">恢复默认</el-button>
</el-row>
<spell :module="spellInfo.module" :spell-data="spellData" :color-config="colorConfig"/>
</el-col>
<el-col :span="14" :offset="1">
<el-card shadow="always">
<el-form class="edit-form" size="mini" ref="editForm" v-model="spellData" label-width="90px">
<el-divider content-position="left">在此填写</el-divider>
<el-row>
<el-col :span="18">
<el-form-item label="名称">
<el-col :span="21">
<el-input v-model="spellData.name" placeholder="技能名称"/>
</el-col>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="热键" label-width="45px">
<el-input v-model="spellData.hotKey" placeholder="热键"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-form-item label="技能描述">
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 3}"
placeholder="例:能召唤出若干次冰片攻击,对目标区域内的单位造成一定的伤害。"
v-model="spellData.effect"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="特点">
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 3}" placeholder="例:需要持续施法"
v-model="spellData.nature"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item>
<template slot="label">
<span>升级描述</span>
<el-tooltip placement="top" effect="light">
<template slot="content">
{}来标记数值的位置{}内用<span style="color:#f00;">各不相同</span>的小写abcd来区分<br>
{a}点伤害晕眩时间{b}<br>
数值的语法:<br>
[lv=3][a=1,2,3][b=20+10]<br>
其中ab与上述数值的标记对应lv=3表示一共有3个等级 <br>
[b=20+10] 20+10表示公式意思是1级是20后面每级+10[a=1,2,3]表示每个等级的数值
</template>
<i class="el-icon-question" style="cursor:pointer;"></i>
</el-tooltip>
</template>
<el-input placeholder="学习技能时显示的“1级 - xx伤害,xx秒时间。”"
v-model="spellData.updateWord.text" @change="handleTempDataForUpdate"/>
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4}"
placeholder="数值"
v-model="tempData.updateWord" @change="handleTempDataForUpdate"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item>
<template slot="label">
<span>普通描述</span>
<el-tooltip placement="top" effect="light">
<template slot="content">
{}来标记数值的位置{}内用<span style="color:#f00;">各不相同</span>的小写abcd来区分<br>
造成{a}点伤害并使其{b}秒内陷入晕眩
数值的语法:<br>
[lv=3][a=1,2,3][b=20+10]<br>
其中ab与上述数值的标记对应lv=3表示一共有3个等级 <br>
[b=20+10] 20+10表示公式意思是1级是20后面每级+10[a=1,2,3]表示每个等级的数值
</template>
<i class="el-icon-question" style="cursor:pointer;"></i>
</el-tooltip>
</template>
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4}"
placeholder="向目标投掷一巨大的魔法锤,对其造成100点伤害并使其3秒内处于眩晕状态。"
v-model="spellData.normalWord.text" @change="handleTempDataForNormal"/>
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4}"
placeholder="数值"
v-model="tempData.normalWord" @change="handleTempDataForNormal"/>
</el-form-item>
</el-row>
<el-divider content-position="left">技能属性</el-divider>
<el-row v-for="(e,i) in spellData.pros" style="margin-bottom: 12px;">
<el-col :span="2" style="line-height: 40px;text-align:right;">
<i class="el-icon-remove" style="font-size: 18px; margin-right: 5px;cursor: pointer;color:#F56C6C;"
@click="spellData.pros = spellData.pros.filter(f=>f!==e)"></i>
</el-col>
<el-col :span="13">
<el-autocomplete class="inline-input" v-model="e.name" placeholder="请输入名称"
:fetch-suggestions="querySearch"></el-autocomplete>
</el-col>
<el-col :span="9">
<el-input v-model="e.val" placeholder="请输入值"/>
</el-col>
</el-row>
<div style="text-align:left;padding-left: 50px;margin-bottom: 20px;">
<el-link type="primary" @click="addSpellPro">添加...</el-link>
</div>
</el-form>
</el-card>
</el-col>
<spell-builder-dialog v-if="spellBuilderCfg.show" :show.sync="spellBuilderCfg.show"
:spell-data="spellBuilderCfg.data" :color-config="colorConfig"/>
</div>
</template>
<script>
import Spell from "@/views/wc3word/spell";
import {conversion} from "@/utils/tools";
import SpellBuilderDialog from "@/views/wc3word/dialog/SpellBuilder";
const default_spell_data = {
id: "A000",
lv: "1",
name: null,
hotKey: null,
effect: null,
pros: [{name: '法力消耗', val: null},],
updateWord: {text: '', vals: []},
nature: undefined,
normalWord: {text: '', vals: []},
}
const default_spell_info = {
module: '学习',
}
const default_spell_pro_list = [
{name: '法力消耗', val: null},
{name: '施法距离', val: null},
{name: '冷却时间', val: null},
{name: '持续时间', val: null},
{name: '法术范围', val: null},
{name: '吟唱时间', val: null},
]
export default {
name: 'Edit',
props: {
colorConfig: Object
},
components: {SpellBuilderDialog, Spell},
data() {
return {
tempData: {},
spellBuilderCfg: {
show: false,
data: null
},
spellDataObj: Object.assign({}, default_spell_data),
spellInfo: Object.assign({}, default_spell_info),
}
},
computed: {
spellData() {
return this.spellDataObj
},
spellDefaultProNames() {
return default_spell_pro_list.map(e => ({value: e.name}))
},
exampleLevelList() {
return this.spellData.updateWord.vals.length || 1
},
},
watch: {
spellDataObj: {
handler(newVal) {
localStorage.setItem('lastSpellData', JSON.stringify(newVal));
},
deep: true //
},
tempData: {
handler(newVal) {
localStorage.setItem('lastTempData', JSON.stringify(newVal));
},
deep: true //
},
},
created() {
if (localStorage.getItem('lastSpellData') != null) {
// console.log(localStorage.getItem('lastSpellData'))
this.spellDataObj = JSON.parse(localStorage.getItem('lastSpellData'))
}
if (localStorage.getItem('lastTempData') != null) {
// console.log(localStorage.getItem('lastTempData'))
this.tempData = JSON.parse(localStorage.getItem('lastTempData'))
}
},
mounted() {
},
methods: {
querySearch(queryString, cb) {
var restaurants = this.spellDefaultProNames;
var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
// callback
cb(results);
},
createFilter(queryString) {
return (restaurant) => {
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
addSpellPro() {
this.spellData.pros.push({})
},
handleResolveTempData(s) {
var sStrList = s.between("[", "]")
var result = []
sStrList.forEach((sStr, i) => {
var vs = sStr.split(",")
result.push(vs)
})
var minLv = result.minFor()
if (!minLv) {
return minLv
}
return result.startCut(minLv)
},
handleTempDataForNormal() {
var ori = this.tempData.normalWord
var ns = this.spellData.normalWord
if (ori && ns.text) {
ns.vals = conversion(ori)
}
},
handleTempDataForUpdate() {
var ori = this.tempData.updateWord
var ns = this.spellData.updateWord
if (ori && ns.text) {
ns.vals = conversion(ori)
}
},
handleBuilder() {
// console.log(' -> ', this.spellData)
this.spellBuilderCfg.show = true
this.spellBuilderCfg.data = Object.assign({}, this.spellData)
},
handleResetSpellData() {
this.spellDataObj = Object.assign({}, default_spell_data)
}
}
}
</script>
<style scoped lang="scss">
.edit-container {
* {
font-weight: bold;
font-size: 12px;
}
.spell-info-setting {
margin-bottom: 15px;
}
.edit-form {
padding-right: 5%;
padding-left: 5%;
overflow-y: auto;
max-height: 68vh;
}
padding-left: 5%;
padding-right: 5%;
max-height: 68vh;
}
</style>

@ -0,0 +1,72 @@
<template>
<div class="app-container">
<el-tabs type="border-card" style="min-height: 50vh;">
<!-- <el-tab-pane>-->
<!-- <span slot="label">简介</span>-->
<!-- <div>这是一个wc3编辑器文本生成器它还在制作中</div>-->
<!-- </el-tab-pane>-->
<el-tab-pane>
<span slot="label"><i class="el-icon-edit"></i>编辑文本</span>
<edit :color-config="colorConfig"/>
</el-tab-pane>
<el-tab-pane>
<span slot="label"><i class="el-icon-setting"></i>色彩</span>
<color :color-default-config="colorConfig" style="padding-left: 3%;padding-right: 3%;"
@updateCfg="updateCfg"/>
</el-tab-pane>
<el-tab-pane>
<span slot="label"><i class="el-icon-tickets"></i>更新日志</span>
<update-record/>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import Color from "@/views/wc3word/color";
import Edit from "@/views/wc3word/edit";
import {defaultColorConfig} from '@/utils/tools'
import UpdateRecord from "@/views/wc3word/updateRecord";
import version from '@/views/wc3word/dialog/version';
export default {
name: 'Word',
components: {UpdateRecord, Edit, Color},
data() {
return {
colorConfig: Object.assign({}, defaultColorConfig),
version: '1.0.0'
}
},
computed: {},
watch: {},
created() {
},
mounted() {
const latestVersion = Object.entries(version).pop() //
const latestSubVersion = Object.keys(latestVersion[1]).pop() //
this.version = `${latestVersion[0]}.${latestSubVersion}`
const h = this.$createElement;
this.$notify({
title: '来自Soul2的提示',
message: h('span', {style: 'color: teal'}, `当前正在使用的生成器版本是${this.version}`),
position: 'bottom-right',
duration: 4000,
// showClose: false
});
},
methods: {
updateCfg(cfg) {
this.colorConfig = cfg
}
}
}
</script>
<style scoped lang="scss">
.app-container {
padding-left: 15%;
padding-right: 15%;
}
</style>

@ -0,0 +1,127 @@
<template>
<div class="spell-container" :style="{fontSize: (fontSize || 12) + 'px'}">
<div v-if="module === '学习'">
<p style="margin-bottom: 3px;">
学习 <span :style="{color: colorConfig.learnLevel}">{{ spellData.lv || '%d' }}</span>
{{ spellData.name || '技能名称' }}
<span v-if="spellData.hotKey">
(<span :style="{color: colorConfig.hotKey}">{{ spellData.hotKey }}</span>)
</span>
</p>
<hr>
<p style="margin-top: 7px;">
{{ spellData.effect }}
<br/>
<span v-if="spellData.nature">
<br><span :style="{color: colorConfig.nature}">{{ spellData.nature }}</span><br>
</span>
<br/>
<span v-if="p.val" v-for="(p,i) in learnPros" :key="i">
<span :style="{color: colorConfig.property}">
{{ p.name }}
</span>
{{ p.key ? `<${spellData.id},${p.key}${p.lv}${p.r ? ',%' : ''}>` : (p.val || '(null)') }}
<br>
</span>
<span v-if="spellData.updateWord && spellData.updateWord.vals"
v-for="(l,i) in spellData.updateWord.vals">
<br>
<span :style="{color: colorConfig.learnUpdateLevel}">{{ (i + 1) }}</span> -
{{ spellData.updateWord.text.format(l) }}
{{ spellData.updateWord.text.endsWith("。") ? null : '。' }}
</span>
</p>
</div>
<div v-if="module === '普通'">
<p style="margin-bottom: 3px;">
{{ spellData.name || '技能名称' }}
<span v-if="spellData.hotKey">(<span :style="{color: colorConfig.hotKey}">{{ spellData.hotKey }}</span>)</span>
-
[<span :style="{color: colorConfig.learnLevel}">{{ spellData.lv || '1' }}</span>]
</p>
<hr>
<p style="margin-top: 7px;">
{{ spellData.normalWord.text.format(spellData.normalWord.vals[spellData.lv - 1]) }}
{{ spellData.normalWord.text.length === 0 || spellData.normalWord.text.endsWith("。") ? null : '。' }}
<br/>
<span v-if="spellData.nature">
<br><span :style="{color: colorConfig.nature}">{{ spellData.nature }}</span><br>
</span>
<br v-if="normalPros.length > 0">
<span v-if="p.val" v-for="(p,i) in normalPros" :key="i">
<span :style="{color: colorConfig.property}">
{{ p.name }}
</span>
{{ p.key ? `<${spellData.id},${p.key}${p.lv}${p.r ? ',%' : ''}>` : (p.val || '(null)') }}
<br>
</span>
</p>
</div>
</div>
</template>
<script>
const default_spell_data = {
id: "A000",
lv: "1",
name: "名称丢失",
hotKey: "Q",
effect: "法术效果丢失",
pros: [],
updateWord: undefined,
nature: undefined,
normalWord: undefined,
}
export default {
name: 'Spell',
props: {
module: {
default: () => '学习',
type: String
},
spellData: {
default: () => Object.assign({}, default_spell_data),
type: Object
},
colorConfig: {
default: () => {
},
type: Object
},
fontSize: Number
},
components: {},
data() {
return {}
},
computed: {
normalPros() {
return this.spellData.pros.filter(e => e.name && e.name !== '法力消耗')
},
learnPros() {
return this.spellData.pros.filter(e => e.name)
}
},
watch: {},
created() {
},
mounted() {
},
methods: {}
}
</script>
<style scoped lang="scss">
.spell-container {
text-align: left;
font-weight: bold !important;
background-color: rgba(0, 0, 0, .75);
color: #ffffff;
border-radius: 5px;
padding: 3%;
box-sizing: border-box;
}
</style>

@ -0,0 +1,55 @@
<template>
<el-collapse v-model="activeNames">
<el-collapse-item class="version" v-for="v in versionList('1.0')" :name="v.v">
<div slot="title" class="version-title">{{ v.v }}</div>
<div class="version-line" v-for="line in v.l">[{{ line.type }}]{{ line.value }}</div>
</el-collapse-item>
</el-collapse>
</template>
<script>
import version from '@/views/wc3word/dialog/version'
export default {
name: 'UpdateRecord',
props: {
version: String
},
components: {},
data() {
return {
activeNames: [],
}
},
computed: {},
watch: {},
created() {
this.activeNames.push(this.versionList('1.0')[0].v)
},
mounted() {
},
methods: {
versionList(pv) {
let keys = Object.keys(version[pv]).sort((a, b) => b - a)
return keys.map(e => ({v: pv + '.' + e, l: version[pv][e]}))
}
}
}
</script>
<style scoped lang="scss">
.version {
&-title {
font-size: 16px;
font-weight: bold;
}
&-line {
padding-left: 5%;
padding-right: 5%;
text-align: left;
font-size: 16px;
font-weight: bold;
}
}
</style>

@ -0,0 +1,8 @@
const wwbTools = {
dyeing: (str, color) => {
const prefix = '|cfff'
const suffix = '|r'
return color ? (prefix + color.replace('#', "") + str + suffix) : str
},
}
export default wwbTools

@ -0,0 +1,153 @@
import wwbTools from '@/views/word_builder/tools/tools'
/* Spell */
const default_spell_module = {
name: null, // 技能名称
hotKey: null, // 热键
learn: { // 学习文本设置
title: null, // 学习标题
tip: { // 学习扩展文本
effect: null, // 效果描述
attr: () => this.attrData.filter(e => !Array.isArray(e)), // 属性
lvEffect: [ // 每个等级的效果描述
// { text: '造成{a}点伤害和{b}秒眩晕', data: [100,3] }
],
},
},
attrData: [
/**
* { name: '法力消耗', value: null }
* or
* { name: '法力消耗', value: [] }
*/
],
normal: { // 普通技能文本
attr: () => this.attrData.filter(e => e.name !== '法力消耗'),
title: null, // 标题
tip: [
/** { text: '造成{a}点伤害和{b}秒眩晕', data: [100,3] } */
]
},
nature: null, // 特点
toWord: (color, module, lv) => {
let result = ''
if (module) {
if (module === 'title') {
if (lv) {
result += `${this.name}(${wwbTools.dyeing(this.hotKey, color.hotKey)})`
result += ` - [${wwbTools.dyeing(lv + '级', color.level)}]`
} else {
lv = '%d'
result += `学习 ${wwbTools.dyeing(lv + '级', color.level)} ${this.name}(${wwbTools.dyeing(this.hotKey, color.hotKey)})`
}
} else if (module === 'uberTip') {
if (lv) { // 有lv,返回普通文本
lv = Math.min(lv, this.normal.tip.length)
let d = this.normal.tip[lv]
result += d.text.format(...d.data)
result += this.nature ? ('\n\n' + wwbTools.dyeing(this.nature, color.nature)) : ''
if (this.normal.attr().length > 0) {
result += ('\n')
this.normal.attr().forEach((e) => {
result += ('\n' + wwbTools.dyeing(e.name, color.property) + ':')
try {
result += (Array.isArray(e.value) ? e.value[lv] : e.value)
} catch (e) {
result += e.value[e.value.length - 1]
}
})
}
} else { // 无lv,返回学习文本
result += (this.learn.tip.effect)
result += this.nature ? ('\n\n' + wwbTools.dyeing(this.nature, color.nature)) : ''
if (this.learn.tip.attr().length > 0) {
result += '\n'
this.learn.tip.attr().forEach((e) => {
result += ('\n' + wwbTools.dyeing(e.name, color.property) + ':')
try {
result += (Array.isArray(e.value) ? e.value[lv] : e.value)
} catch (e) {
result += e.value[e.value.length - 1]
}
})
}
if (this.learn.tip.lvEffect?.length > 0) {
result += '\n'
this.learn.tip.lvEffect.forEach((e, i) => {
result += ('\n' + wwbTools.dyeing((i + 1) + '级 - ', color.learnUpdateLevel))
result += (e.text.format(...e.data))
})
}
}
}
}
return result
},
}
/* Unit */
const default_unit_module = {
name: null, // 单位名称
desc: null, // 单位描述,可填充数据项
descValues: null, // 单位描述数据
hotKey: null, // 热键
spells: [ // 技能列表,可以是对象列表,也可以是字符串列表
{
name: null, // 技能名称
desc: null, // 技能简述,不可填充数据,可选项
}, {
name: null, // 技能名称
desc: null, // 技能简述,不可填充数据,可选项
},
],
nature: null, // 特点
attack: { // 攻击力设置
max: null, // 攻击力上限
min: null, // 攻击力下限
dice: { // 骰子设置
count: null, // 骰子个数
sides: null, // 骰子面数
},
type: null, // 攻击力类型
range: null, // 射程
},
hp: null, // 最大生命值
mp: null, // 最大法力值
armor: { // 护甲设置
value: null, // 护甲值
type: null // 护甲类型
},
}
/* item */
const default_item_module = {
overlapping: false, // 是否可叠加,默认否
hotKey: null, // 热键
uses: 0, // 使用次数,默认是0
price: 125, // 价格,默认是125
desc: { // 说明设置
tip: null, // 放地上鼠标点击显示的文本提示
title: null, // 标题
uberTip: null, // 扩展
},
cd: { // 冷却时间,默认不显示
show: false,
value: 0
},
beLost: true, // 可以被丢弃
beSold: true, // 可卖给商店
attributes: [ // 属性
{
type: 'gain', // gain=增益;reduce=减损;spell=技能
name: null, // 属性名称,类型为spell时为技能名
tip: null, // 技能描述,类型是spell时显示
value: null, // 属性值,类型是spell时不显示
},
/**
* example: { type: gain, name: 力量, value: 3} -> result: 力量+3
* example: { type: reduce, name: 力量, value: 3} -> result: |cffff0000力量-3|r
* example: { type: spell, name: 能量冲击, tip: 召唤能量光柱攻击敌人造成100点伤害和3秒眩晕} ->
* result: |cff00ff00能量冲击|r|n召唤能量光柱攻击敌人造成100点伤害和3秒眩晕
*/
],
}
Loading…
Cancel
Save