新增war3技能文本生成

soul2/wc3word
soul2 2 years ago
parent 7ded80703a
commit bc96eaa91a
  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. 53
      src/utils/StringUtils.js
  11. 195
      src/utils/tools.js
  12. 4
      src/views/home/index.vue
  13. 4
      src/views/sodemo/index.vue
  14. 3
      src/views/soui/index.vue
  15. 272
      src/views/wc3word/color.vue
  16. 184
      src/views/wc3word/dialog/SpellBuilder.vue
  17. 51
      src/views/wc3word/dialog/updateRecord.vue
  18. 286
      src/views/wc3word/edit.vue
  19. 63
      src/views/wc3word/index.vue
  20. 127
      src/views/wc3word/spell.vue

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

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

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

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

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

@ -46,3 +46,4 @@
.breadcrumb-leave-active {
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,53 @@
/**
* 调用示例
*
* 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;
}
}
/**
* 取出所有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,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>
<style scoped>
#home {
padding-top: 20px;
}
#dl-btn .el-button {
margin-top: 7px;
}

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

@ -63,4 +63,7 @@ export default {
</script>
<style scoped>
#soui {
padding-top: 20px;
}
</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 = '|cfff'
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,51 @@
<template>
<el-dialog ref="dialogForm" width="45%" :title="title" :visible.sync="visible" @close="closeDialog"
:append-to-body="true" :show-close="false">
<!-- <div slot="footer" class="dialog-footer">-->
<!-- <el-button @click="visible = false">取消</el-button>-->
<!-- <el-button type="primary" @click="handleSave">保存</el-button>-->
<!-- </div>-->
</el-dialog>
</template>
<script>
export default {
name: 'UpdateRecordDialog',
props: {
show: {
type: Boolean,
default: () => false
}
},
components: {},
data() {
return {
visible: this.show,
}
},
computed: {
title() {
return '更新记录'
}
},
watch: {
visible() {
this.$emit('update:show', false)
}
},
created() {
},
mounted() {
},
methods: {
closeDialog() {
//
},
}
}
</script>
<style scoped lang="scss">
</style>

@ -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,63 @@
<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-tabs>
</div>
</template>
<script>
import Color from "@/views/wc3word/color";
import Edit from "@/views/wc3word/edit";
import {defaultColorConfig} from '@/utils/tools'
export default {
name: 'Word',
components: {Edit, Color},
data() {
return {
colorConfig: Object.assign({}, defaultColorConfig),
version: '1.0.3'
}
},
computed: {},
watch: {},
created() {
},
mounted() {
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>
Loading…
Cancel
Save