官网:https://www.antdv.com/docs/vue/introduce-cn/
methods: {
setRowClassName(record, index) {
return index % 2 === 1 ? 'ant-table-row-twoe' : 'ant-table-row-once'
}
}
// 添加全局样式
.ant-table-row-once {
background-color: #ffffff;
}
.ant-table-row-twoe {
background-color: #fafafa;
}
.ant-table-thead > tr > th,
.ant-table-tbody > tr > td {
padding: 8px 8px;
}
{
"extensions.ignoreRecommendations": true,
"eslint.enable": false,
"editor.wordWrapColumn": 120,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"vetur.validation.template": false
}
{
// vscode默认启用了根据文件类型自动设置tabsize的选项
"editor.detectIndentation": false,
// 重新设定tabsize
"editor.tabSize": 4,
// #值设置为true时,每次保存的时候自动格式化;值设置为false时,代码格式化请按shift+alt+F
"editor.formatOnSave": false,
// #每次保存的时候将代码按eslint格式进行修复
"eslint.autoFixOnSave": true,
// 添加 vue 支持
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true
}
],
// #让prettier使用eslint的代码格式进行校验
"prettier.eslintIntegration": true,
// #去掉代码结尾的分号
"prettier.semi": false,
// #使用带引号替代双引号
"prettier.singleQuote": true,
"prettier.tabWidth": 4,
// #让函数(名)和后面的括号之间加个空格
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
// #这个按用户自身习惯选择
"vetur.format.defaultFormatter.html": "js-beautify-html",
// #让vue中的js按"prettier"格式进行格式化
"vetur.format.defaultFormatter.js": "prettier",
"vetur.format.defaultFormatterOptions": {
"js-beautify-html": {
// #vue组件中html代码格式化样式
"wrap_attributes": "force-aligned", //也可以设置为“auto”,效果会不一样
"wrap_line_length": 200,
"end_with_newline": false,
"semi": false,
"singleQuote": true
},
"prettier": {
"semi": false,
"singleQuote": true
}
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// 格式化stylus, 需安装Manta's Stylus Supremacy插件
"stylusSupremacy.insertColons": false, // 是否插入冒号
"stylusSupremacy.insertSemicolons": false, // 是否插入分号
"stylusSupremacy.insertBraces": false, // 是否插入大括号
"stylusSupremacy.insertNewLineAroundImports": false, // import之后是否换行
"stylusSupremacy.insertNewLineAroundBlocks": false,
"prettier.useTabs": true,
"files.autoSave": "off",
"explorer.confirmDelete": false,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"diffEditor.ignoreTrimWhitespace": false // 两个选择器中是否换行
}
// 1,在util.js中添加函数
// 2,在main.js中添加引用
// 3,调用
/**
* 依据code,返回常数代码对应的文本
* @param value 常数代码code
* @param codeType 常数代码
*/
export default {
install(Vue) {
Vue.prototype.getCodeText = function (value, codeType) {
var text = ''
this.$store.getters.items[codeType].forEach((item, index, arr) => {
if (value != null && value.toString() === item.value) {
text = item.text
}
})
return text
}
}
}
import util from './utils/util'
Vue.use(util)
{
title: '报告生成状态',
dataIndex: 'generateStatus',
customRender: value => {
return this.getCodeText(value, 'code_rep_cre_code')
}
},
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
你可以在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
或者在创建 Vue 实例之前全局定义过滤器
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
过滤器可以串联:
{{ message | filterA | filterB }}
在这个例子中,filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递到 filterB 中。
过滤器是 JavaScript 函数,因此可以接收参数:
{{ message | filterA('arg1', arg2) }}
这里,filterA 被定义为接收三个参数的过滤器函数。其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。
Vue.filter('moment', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
return moment(dataStr).format(pattern)
})
import './utils/filter'
{
title: '最近一次生成时间',
dataIndex: 'lastGenerateTime',
scopedSlots: { customRender: 'lastGenerateTime' }
},
<span slot="lastGenerateTime" slot-scope="text">
<span>{{ text | moment }}</span>
</span>
官网:
https://pro.loacg.com/docs/style
如何在 Vue 中优雅地使用 CSS Modules?
https://juejin.im/post/5ac5fd7f5188257cc20d854e
覆盖组件样式:
<template>
<div class="test-wrapper">
<a-select>
<a-select-option value="1">Option 1a-select-option>
<a-select-option value="2">Option 2a-select-option>
<a-select-option value="3">Option 3a-select-option>
a-select>
div>
template>
<script>
export default {
}
script>
<style lang="less" scoped>
// 使用 css 时可以用 >>> 进行样式穿透
.test-wrapper >>> .ant-select {
font-size: 16px;
}
// 使用 scss, less 时,可以用 /deep/ 进行样式穿透
.test-wrapper /deep/ .ant-select {
font-size: 16px;
}
style>
<li v-for="article in articles" @click="getDescribe(article.id)">
方案1 path带参数
getDescribe(id) {
// 直接调用$router.push 实现携带参数的跳转
this.$router.push({
path: `/describe/${id}`,
})
// 路由配置如下
{
path: '/describe/:id',
name: 'Describe',
component: Describe
}e
方案2 父组件中:通过路由属性中的name来确定匹配的路由,通过params来传递参数。
this.$router.push({
name: 'Describe',
params: {
id: id
}
})
// 路由配置
{
path: '/describe',
name: 'Describe',
component: Describe
}
// 子组件中: 这样来获取参数
this.$route.params.id
方案3通过query来传递参数
this.$router.push({
path: '/describe',
query: {
id: id
}
})
{
path: '/describe',
name: 'Describe',
component: Describe
}
this.$route.query.id
2,ink跳转传参:
import Link from 'umi/link';
<Link to={{
pathname: '/api-manage/create-sub-system',
query: {
id: 6,
value: 'lala',
}
}}>
<Button
style={{ marginLeft: 8 }}
type="primary"
// onClick={this.onCreate}
>
<Icon type="plus" />
创建
</Button>
</Link>
1)自己实现
<a-input allowClear placeholder="请输入分位值区间" @blur="checkTitle">
// 校验标题重复
checkTitle(e) {
const title = e.target.value
// HrReptSetConstModelController /checkTitle/{templateId}/{constType}/{title}
if (e.target.value) {
const arr = [{
message: '您输入的手机格式不正确!',
field: 'constNameZH'
}]
this.form.setFields({ constNameZH: { value: e.target.value, errors: arr } })
}
console.log(title)
},
2,利用vue自带方法
v-decorator="['constNameEN', {initialValue: mdl.constNameEN, rules: [{validator: checkTitle}]}]"
// 校验标题重复
checkTitle(rule, value, callback) {
if (value) {
// /rept/consts/checkTitle/{templateId}/{constType}/{title}
const field = rule.fullField
let langMark = 'zh-CN'
if (field.substring(field.length - 2) === 'EN') {
langMark = 'en-US'
} else if (field.substring(field.length - 2) === 'JP') {
langMark = 'ja-JP'
}
// 新增校验url
let url = '/rept/consts/checkTitle/' + this.templateId + '/' + 0 + '/' + value + '/' + langMark
if (this.constId) {
// 修改校验url
url = '/rept/consts/checkTitleEdit/' + this.templateId + '/' + 0 + '/' + value + '/' + langMark
}
api.get(url).then(res => {
if (res === 'NG') {
const error = '该分位值区间已被使用,请重新输入'
callback(error)
} else {
callback()
}
})
} else {
callback()
}
},
<a-form-item label="正文描述:">
<a-textarea ref="contentArea" rows="10" placeholder="请输入正文描述" v-decorator="[ 'guideDescribeZH', {initialValue: mdl.guideDescribe, rules: [{ max: 2000, message: '最大长度不能超过2000' }]}]"/>
<div style="margin-bottom:-24px;"><a @click="handlerA('ZH')">有效评估人数</a><a style="margin-left:12px;" @click="handlerA('ZH')">活动开启时间</a><a style="margin-left:12px;" @click="handlerA('ZH')">活动结束时间</a></div>
</a-form-item>
// 关于评估数据样本,点击链接字体时
handlerA(type) {
const elInput = this.$refs.contentArea.$el
const startPos = elInput.selectionStart// input 第0个字符到选中的字符
const endPos = elInput.selectionEnd // 选中的字符到最后的字符
if (startPos === undefined || endPos === undefined) return
// 将文字添加到选中的光标位置
const innerText = '#' + event.target.text + '#'
let sourceText = ''
if (type === 'ZH') {
sourceText = this.form.getFieldValue('guideDescribeZH')
} else if (type === 'EN') {
sourceText = this.form.getFieldValue('guideDescribeEN')
} else {
sourceText = this.form.getFieldValue('guideDescribeJP')
}
const result = sourceText.substring(0, startPos) + innerText + sourceText.substring(endPos)
elInput.value = result
// 重新定义光标位置
elInput.focus()
elInput.selectionStart = startPos + innerText.length
elInput.selectionEnd = startPos + innerText.length
if (type === 'ZH') {
this.form.setFieldsValue({
guideDescribeZH: result
})
} else if (type === 'EN') {
this.form.setFieldsValue({
guideDescribeEN: result
})
} else {
this.form.setFieldsValue({
guideDescribeJP: result
})
}
},
src\views\evaluation\setting\modules\ModeForm.vue
<template>
<a-modal
:title="title"
:width="width"
:visible="visible"
:confirmLoading="confirmLoading"
:footer="null"
:maskClosable="false"
:afterClose="afterClose"
@cancel="handleCancel"
@ok="handleSubmit"
>
<a-spin :spinning="confirmLoading" class="parent">
<a-tabs :activeKey="activeKey" @change="changeTab" :tabBarStyle="{ textAlign: 'right', borderBottom: 'set' }">
<a-tab-pane tab="中文" key="zh-CN">
<a-form :form="form" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
<a-form-item label="标题:">
<a-input allowClear placeholder="请输入标题" v-decorator="['guideTitleZH', {initialValue: mdl.guideTitle, rules: [{ required: true, message: '请输入标题' },{ max: 100, message: '最大长度不能超过100' }]}]" />
a-form-item>
<div v-if="guideType === '2'">
<a-form-item label="正文描述:">
<a-textarea rows="10" placeholder="请输入正文描述" v-decorator="[ 'guideDescribeZH', {initialValue: mdl.guideDescribe, rules: [{ max: 2000, message: '最大长度不能超过2000' }]}]"/>
a-form-item>
div>
<div v-if="guideType === '7'">
<a-form-item label="正文描述:">
<a-textarea ref="contentArea" rows="10" placeholder="请输入正文描述" v-decorator="[ 'guideDescribeZH', {initialValue: mdl.guideDescribe, rules: [{ max: 2000, message: '最大长度不能超过2000' }]}]"/>
<div style="margin-bottom:-24px;"><a @click="handlerA('ZH')">有效评估人数a><a style="margin-left:12px;" @click="handlerA('ZH')">活动开启时间a><a style="margin-left:12px;" @click="handlerA('ZH')">活动结束时间a>div>
a-form-item>
<a-form-item label="作答统计:">
<a-radio-group v-decorator="['isShow', {initialValue: mdl.isShow }]">
<a-radio :value="1">显示a-radio>
<a-radio :value="0">不显示a-radio>
a-radio-group>
a-form-item>
div>
<div v-if="guideType === '8'">
<a-form-item label="正文描述:" required :validate-status="validateStatusZH" :help="helpZH">
<vue-ueditor-wrap v-model="guideDescribeZh" :config="myConfig">vue-ueditor-wrap>
a-form-item>
div>
<div v-if="guideType !== '8' && guideType !== '7' && guideType !== '2'">
<a-form-item label="正文描述:">
<a-textarea rows="10" placeholder="请输入正文描述" v-decorator="[ 'guideDescribeZH', {initialValue: mdl.guideDescribe, rules: [{ required: true, message: '请输入正文描述' },{ max: 2000, message: '最大长度不能超过2000' }]}]"/>
a-form-item>
div>
a-form>
a-tab-pane>
a-tabs>
<div style="text-align: center;padding-bottom: 24px;">
<a-button icon="check-circle" type="primary" html-type="submit" @click="handleSubmit()">{{ this.global.BTN.SAVE }}a-button>
<a-button icon="close-circle" style="margin-left: 8px" @click="handleCancel()">{{ this.global.BTN.CANCEL }}a-button>
div>
a-spin>
a-modal>
template>
<script>
import { api } from '@/api/api'
import VueUeditorWrap from 'vue-ueditor-wrap'
export default {
data() {
return {
formItemLayout: {
labelCol: { xs: { span: 24 }, sm: { span: 5 } },
wrapperCol: { xs: { span: 24 }, sm: { span: 16 } }
},
title: '新增',
width: 640,
visible: false,
confirmLoading: false,
modelFlag: '', // 父页面传递参数表示add,edit
guideId: null, // 父页面传递参数:指南业务主键
setModuleId: null, // 父页面传递参数:模块库系统主键
guideType: null,
activeKey: 'zh-CN',
guideDescribeZh: '',
guideDescribeEn: '',
guideDescribeJp: '',
validateStatusZH: 'validating',
validateStatusEN: 'validating',
validateStatusJP: 'validating',
helpZH: '',
helpEN: '',
helpJP: '',
mdl: {},
mdlEN: {},
mdlJP: {},
form: this.$form.createForm(this),
myConfig: {
// 编辑器不自动被内容撑高
autoHeightEnabled: false,
// 初始容器高度
initialFrameHeight: 240,
enableAutoSave: false,
maximumWords: 5000,
// 初始容器宽度
initialFrameWidth: '100%',
imageActionName: 'uploadimage',
imageAllowFiles: ['.png', '.jpg', '.jpeg', '.gif', '.bmp'],
imageFieldName: 'file',
imageUrlPrefix: process.env.VUE_APP_API_FILE_PREFIX_URL,
// 上传文件接口(这个地址是我为了方便各位体验文件上传功能搭建的临时接口,请勿在生产环境使用!!!)
serverUrl: '/files',
/* toolbars: [
['fullscreen', 'source', 'undo', 'redo'],
['bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', 'insertimage', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc']
], */
// UEditor 资源文件的存放路径,如果你使用的是 vue-cli 生成的项目,通常不需要设置该选项,vue-ueditor-wrap 会自动处理常见的情况,如果需要特殊配置,参考下方的常见问题2
UEDITOR_HOME_URL: '/UEditor/'
}
}
},
methods: {
// 接收父页面数据完成页面初期化
// modelFlag标记操作add:添加,edit编辑
// guide编辑的时候传递的行数据,包含指南的业务id和类型
// setModuleId 指南业务主键
init(modelFlag, guide, setModuleId) {
this.visible = true
this.modelFlag = modelFlag
this.setModuleId = setModuleId
// 修改:动态获取显示数据
if (guide) {
this.title = '编辑'
this.guideId = guide.guideId
this.guideType = guide.guideType
// 关于能力模型,富文本
if (this.guideType === '8') {
this.width = 1048
}
let url = '/rept/guides/getGuide/' + this.guideId + '/' + guide.setModuleId
if (this.modelFlag === 'libEdit') {
url = '/rept/guides/getLibGuide/' + this.guideId
}
// HrReptSetGuideController
api.get(url).then(res => {
if (res) {
this.mdl = res['zh-CN']
this.mdlEN = res['en-US']
this.mdlJP = res['ja-JP']
if (this.guideType === '8') {
this.guideDescribeZh = this.mdl.guideDescribe
this.guideDescribeEn = this.mdlEN.guideDescribe
this.guideDescribeJp = this.mdlJP.guideDescribe
}
}
})
}
},
// 执行保存
handleSubmit() {
// 关于能力模型
this.errorFlag = true
if (this.guideType === '8') {
// 校验中文
if (!this.guideDescribeZh) {
this.helpZH = '请输入正文描述'
this.validateStatusZH = 'error'
this.errorFlag = false
} else {
if (this.guideDescribeZh.length > 5000) {
this.helpZH = '最大长度不能超过5000'
this.validateStatusZH = 'error'
this.errorFlag = false
}
}
// 校验英文
/* if (!this.guideDescribeEn) {
this.helpEN = '请输入正文描述'
this.validateStatusEN = 'error'
this.errorFlag = false
} else {
if (this.guideDescribeEn.length > 5000) {
this.helpEN = '最大长度不能超过5000'
this.validateStatusEN = 'error'
this.errorFlag = false
}
} */
// 校验日文
/* if (!this.guideDescribeJp) {
this.helpJP = '请输入正文描述'
this.validateStatusJP = 'error'
this.errorFlag = false
} else {
if (this.guideDescribeJp.length > 5000) {
this.helpJP = '最大长度不能超过5000'
this.validateStatusJP = 'error'
this.errorFlag = false
}
} */
}
this.form.validateFields((errors, values) => {
if (!errors && this.errorFlag) {
// 设置中文
this.mdl.guideTitle = values.guideTitleZH
this.mdl.guideDescribe = values.guideDescribeZH || this.guideDescribeZh
// 设置英文
// this.mdlEN.guideTitle = values.guideTitleEN
// this.mdlEN.guideDescribe = values.guideDescribeEN || this.guideDescribeEn
// 设置日文
// this.mdlJP.guideTitle = values.guideTitleJP
// this.mdlJP.guideDescribe = values.guideDescribeJP || this.guideDescribeJp
// 关于评估数据样本
if (this.guideType === '7') {
this.mdl.isShow = values.isShow
// this.mdlEN.isShow = values.isShow
// this.mdlJP.isShow = values.isShow
}
// 执行添加操作时,设置默认参数
if (this.modelFlag === 'add') {
this.mdl.setModuleId = this.setModuleId
this.mdl.langMark = 'zh-CN'
this.mdl.isShow = 1
/* this.mdlEN.setModuleId = this.setModuleId
this.mdlEN.langMark = 'en-US'
this.mdlEN.isShow = 1
this.mdlJP.setModuleId = this.setModuleId
this.mdlJP.langMark = 'ja-JP'
this.mdlJP.isShow = 1 */
}
// 执行系统模板保存操作
if (this.modelFlag === 'libEdit') {
this.mdl.setModuleId = this.setModuleId
// this.mdlEN.setModuleId = this.setModuleId
// this.mdlJP.setModuleId = this.setModuleId
}
// 设置传入的中日英数组
const guides = []
guides[0] = this.mdl
// guides[1] = this.mdlEN
// guides[2] = this.mdlJP
values['guides'] = guides
values['guideId'] = this.guideId
values['setModuleId'] = this.setModuleId
this.confirmLoading = true
// addLibguide系统模板,addOrUpdateGuide自定义
let url = '/rept/guides/addOrUpdateGuide'
if (this.modelFlag === 'libEdit') {
url = '/rept/guides/addLibguide'
}
api.post(url, values).then(res => {
this.$message.success(this.global.SAVE_SUCCESS)
this.confirmLoading = false
this.handleCancel()
this.$emit('ok')
})
} else {
// this.$message.error('请您将中英日三个模块内容填写完整,再进行保存操作。')
this.confirmLoading = false
}
})
},
// 取消
handleCancel() {
this.visible = false
},
// 关于评估数据样本,点击链接字体时
handlerA(type) {
const elInput = this.$refs.contentArea.$el
const startPos = elInput.selectionStart// input 第0个字符到选中的字符
const endPos = elInput.selectionEnd // 选中的字符到最后的字符
if (startPos === undefined || endPos === undefined) return
// 将文字添加到选中的光标位置
const innerText = '#' + event.target.text + '#'
let sourceText = ''
if (type === 'ZH') {
sourceText = this.form.getFieldValue('guideDescribeZH')
} else if (type === 'EN') {
sourceText = this.form.getFieldValue('guideDescribeEN')
} else {
sourceText = this.form.getFieldValue('guideDescribeJP')
}
const result = sourceText.substring(0, startPos) + innerText + sourceText.substring(endPos)
elInput.value = result
// 重新定义光标位置
elInput.focus()
elInput.selectionStart = startPos + innerText.length
elInput.selectionEnd = startPos + innerText.length
if (type === 'ZH') {
this.form.setFieldsValue({
guideDescribeZH: result
})
} else if (type === 'EN') {
this.form.setFieldsValue({
guideDescribeEN: result
})
} else {
this.form.setFieldsValue({
guideDescribeJP: result
})
}
},
// 切换tab
changeTab(key) {
this.activeKey = key
},
// 窗口关闭后初期化控件参数
afterClose() {
this.form.resetFields()
this.activeKey = 'zh-CN'
this.guideId = null
this.guideType = null
this.width = 640
this.guideDescribeZh = ''
this.guideDescribeEn = ''
this.guideDescribeJp = ''
this.mdl = {}
this.mdlEN = {}
this.mdlJP = {}
}
},
components: {
VueUeditorWrap
}
}
script>
<style scoped>
.parent >>> .edui-default .edui-toolbar {
line-height: initial;
}
.parent >>> .edui-default .edui-toolbar .edui-combox .edui-combox-body {
line-height: initial;
}
.parent >>> .ant-tabs-bar {
border-bottom: 1px solid #fff;
}
style>
<template>
<a-modal
:title="title"
:width="800"
:visible="visible"
:confirmLoading="confirmLoading"
:footer="null"
:maskClosable="false"
:afterClose="afterClose"
@cancel="handleCancel"
@ok="handleSubmit"
>
<a-spin :spinning="confirmLoading" class="parent">
<a-tabs :activeKey="activeKey" @change="changeTab" :tabBarStyle="{ textAlign: 'right', borderBottom: 'set' }">
<a-tab-pane tab="中文" key="zh-CN">
<a-form :form="form" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
<a-form-item label="认知结果:" :help="titleMsg" :validateStatus="titleErrorStatus">
<a-input allowClear @change="checkTitle('zh-CN')" placeholder="请输入认知结果" v-decorator="['constNameZH', {initialValue: mdl.constNameZH, rules: [{ required: true, message: '请输入认知结果' },{ max: 20, message: '最大长度不能超过20' }]}]" />
a-form-item>
<a-form-item label="说明:">
<a-textarea rows="4" placeholder="请输入说明" v-decorator="[ 'constDescZH', {initialValue: mdl.constDescZH, rules: [{ max: 500, message: '最大长度不能超过500' }]}]"/>
a-form-item>
<a-form-item label="计算规则" :required="true" :help="formErrMessage" :validateStatus="errorStatus">
<div v-for="rule in constRules" :key="rule.showOrder">
<a-select allowClear @change="checkRuleleft(rule)" placeholder="请选择" style="width:128px;margin-right:8px;" v-model="rule.ruleLeft">
<a-select-option value="0">问卷自评总分a-select-option>
<a-select-option value="4">问卷他评总分a-select-option>
a-select>
<span>-span>
<a-select allowClear @change="checkRuleleft(rule)" placeholder="请选择" style="width:128px;margin-right:8px;margin-left:8px;" v-model="rule.ruleRight">
<a-select-option value="0">问卷自评总分a-select-option>
<a-select-option value="4">问卷他评总分a-select-option>
a-select>
<a-select allowClear placeholder="请选择" style="width:88px;margin-right:8px;" v-model="rule.computeSign">
<a-select-option v-for="item in $store.getters.items.code_compute_sign" :key="item.code" :value="item.code">{{ item.codeName }}a-select-option>
a-select>
<a-input-number :precision="1" :min="0" :max="100" style=" width:65px;margin-right:5px;" v-model="rule.ruleValue"/>
<span>分span>
<img @click="addRuleInterval(rule)" src="@/image/add.png" style="margin-left: 12px;width:11px; height:12px;"/>
<img v-if="constRules.length !== 1" @click="removeRuleInterval(rule)" src="@/image/close.png" style="margin-left:12px;width:11px; height:12px;"/>
div>
a-form-item>
<a-form-item label="规则间运算逻辑:">
<a-select allowClear placeholder="请选择" v-decorator="['arithLogic', { initialValue: mdl.arithLogic, rules: [{ required: true, message: '请选择规则间运算逻辑' }] }]">
<a-select-option v-for="item in this.$store.getters.items.code_arith_logic" :key="item.code" :value="item.code" >{{ item.codeName }}a-select-option>
a-select>
a-form-item>
a-form>
a-tab-pane>
a-tabs>
<div style="text-align: center;padding-bottom: 24px;">
<a-button icon="check-circle" type="primary" html-type="submit" @click="handleSubmit()">{{ this.global.BTN.SAVE }}a-button>
<a-button icon="close-circle" style="margin-left: 8px" @click="handleCancel()">{{ this.global.BTN.CANCEL }}a-button>
div>
a-spin>
a-modal>
template>
<script>
import { api } from '@/api/api'
export default {
data() {
return {
formItemLayout: {
labelCol: { xs: { span: 24 }, sm: { span: 5 } },
wrapperCol: { xs: { span: 24 }, sm: { span: 17 } }
},
title: '新增认知结果',
visible: false,
confirmLoading: false,
activeKey: 'zh-CN',
templateId: 0,
constId: null,
constRules: [{ showOrder: 0 }],
mdl: {},
form: this.$form.createForm(this),
formErrMessage: null,
errorStatus: null,
titleMsg: null,
titleErrorStatus: null,
showOrderHome: 1
}
},
computed: {
evalRelation() {
let arr = []
if (this.$store.getters.items && this.$store.getters.items.code_eval_relation) {
arr = this.$store.getters.items.code_eval_relation
}
return arr.filter(item => (item.code === '4' || item.code === '0'))
}
},
methods: {
// 接收父页面数据完成页面初期化
init(templateId, constId) {
this.templateId = templateId
this.visible = true
// 修改:动态获取显示数据
if (constId) {
this.title = '编辑认知结果'
this.constId = constId
// HrReptSetConstModelController
// constType=0:关于认知结果
api.get('/rept/consts/getConst/' + this.constId + '/' + this.templateId + '/0').then(res => {
if (res) {
this.mdl = {}
this.mdl = res
this.showOrderHome = res.showOrderHome
this.constRules = res.constRules
}
})
}
},
// 执行保存
handleSubmit() {
this.formErrMessage = null
this.errorStatus = null
let errorFlag = false
// 校验计算规则
this.constRules.forEach((val, index) => {
if (!val.ruleLeft || !val.ruleRight || !val.computeSign || (!val.ruleValue && val.ruleValue !== 0)) {
this.formErrMessage = '请输入完整的计算规则'
this.errorStatus = 'error'
errorFlag = true
return false
}
if (val.ruleLeft && val.ruleRight && val.ruleLeft === val.ruleRight) {
this.formErrMessage = '选项1和2不能重复'
this.errorStatus = 'error'
errorFlag = true
return false
}
})
this.form.validateFields((errors, values) => {
if (!values['constNameZH']) {
this.titleMsg = '请输入认知结果'
this.titleErrorStatus = 'error'
}
if (!errors && !errorFlag && !this.titleErrorStatus) {
values['constRules'] = this.constRules
values['templateId'] = this.templateId
values['constId'] = this.constId
values['constType'] = '0' // 0:关于认知结果
values['showOrderHome'] = this.showOrderHome
this.confirmLoading = true
// HrReptSetConstModelController
api.post('/rept/consts/addOrUpdateConst', values).then(res => {
this.$message.success(this.global.SAVE_SUCCESS)
this.confirmLoading = false
this.handleCancel()
this.$emit('ok')
})
} else {
this.confirmLoading = false
}
})
},
// 校验标题
checkTitle(langMark) {
this.titleMsg = null
this.titleErrorStatus = null
const value = event.target.value
// { required: true, message: '请输入认知结果' },{ max: 20, message: '最大长度不能超过20' }
if (value) {
if (value.length > 20) {
this.titleMsg = '最大长度不能超过20'
this.titleErrorStatus = 'error'
return false
}
// 校验查询条件集
const values = {
'templateId': this.templateId,
'constId': this.constId,
'langMark': langMark,
'constType': '0',
'constName': value
}
api.post('/rept/consts/checkTitle', values).then(res => {
if (res === 'NG') {
this.titleMsg = '该认知结果已被使用,请重新输入'
this.titleErrorStatus = 'error'
} else {
this.titleMsg = null
this.titleErrorStatus = null
}
})
} else {
this.titleMsg = '请输入认知结果'
this.titleErrorStatus = 'error'
return false
}
},
checkRuleleft(rule) {
this.formErrMessage = null
this.errorStatus = null
if (rule.ruleLeft && rule.ruleRight && rule.ruleLeft === rule.ruleRight) {
this.formErrMessage = '选项1和2不能重复'
this.errorStatus = 'error'
return false
}
},
// 取消
handleCancel() {
this.visible = false
},
// 切换tab
changeTab(key) {
this.activeKey = key
},
// 窗口关闭后初期化控件参数
afterClose() {
this.form.resetFields()
this.formErrMessage = null
this.errorStatus = null
this.titleMsg = null
this.titleErrorStatus = null
this.activeKey = 'zh-CN'
this.constRules = [{ showOrder: 0 }]
this.mdl = {}
this.constId = null
this.showOrderHome = 1
this.title = '新增认知结果'
},
// 添加元素
addRuleInterval() {
const len = this.constRules.length
this.constRules.push({ showOrder: len })
},
// 删除元素
removeRuleInterval(item) {
const len = this.constRules.length
if (len === 1) {
return
}
this.constRules.splice(item.showOrder, 1)
var newLen = this.constRules.length
if (item.showOrder !== len - 1) {
for (var i = 0; i < newLen; i++) {
const constRules = this.constRules[i]
constRules.showOrder = i
}
}
}
}
}
script>
<style scoped>
.parent >>> .ant-select-disabled .ant-select-selection {
background: white;
cursor: not-allowed;
}
.parent >>> .ant-input-number-disabled .ant-input-number-input {
background: white;
cursor: not-allowed;
}
.parent >>> .ant-tabs-bar {
border-bottom: 1px solid #fff;
}
style>
<a-table
style="margin: 0 30px 0 30px;"
ref="table"
:rowKey="record => record.id"
:columns="columns3"
:data-source="loadData3"
:pagination="false"
>
<span slot="computeRule3" slot-scope="text">
<template>
<span v-html="text">span>
template>
span>
<span slot="action3" slot-scope="text, record">
<template>
<a @click="$refs.cognitiveBias.create(parseInt(templateId),'edit',record,language)">编辑a>
<a style="margin-left:12px;" @click="deleteRecord(record.constId)">删除a>
template>
span>
a-table>
columns3: [
{
dataIndex: 'constName',
title: '认知偏差',
width: '20%'
},
{
dataIndex: 'constDesc',
title: '说明',
width: '30%'
},
{
dataIndex: 'computeRule',
title: '计算规则',
width: '20%',
scopedSlots: { customRender: 'computeRule3' }
},
{
dataIndex: 'arithLogic',
title: '规则间运算逻辑',
width: '20%',
customRender: value => {
return this.getCodeText(value, 'code_arith_logic')
}
},
{
dataIndex: 'action',
title: '操作',
width: '10%',
scopedSlots: { customRender: 'action3' }
}
],
// 获取列表数据
getGridData() {
api.get('/rept/consts/getGridData/' + this.templateId).then(res => {
this.loadData0 = res.constType0
this.loadData1 = res.constType1
this.loadData2 = res.constType2
this.loadData3 = res.constType3
this.loadData4 = res.constType4
this.chartData = res.chartList[0].chartData
this.maxRuleValue = res.chartList[0].maxRuleValue
})
},
{
title: '模块',
dataIndex: 'moduleName',
width: '20%',
customRender: (value, row, index) => {
const obj = {
children: value,
attrs: {}
}
obj.attrs.rowSpan = row.normModuleCount
return obj
},
customCell: (record, rowIndex) => {
const cellStyle =
'background: #ffffff;text-align: left;border:2px solid #ffffff '
return { style: cellStyle }
}
},
主页面调用
<div v-if="this.chartData.length > 0" style="height:649px;margin: 41px 30px 0 30px;">
<div style="margin: 0 0 0px 30px;font-weight: bold;">预览:div>
<div style="width:695px; height:592px;margin: 36px auto 0;">
<report-abstract-rects :chartData="chartData" :maxRuleValue="maxRuleValue">report-abstract-rects>
div>
div>
坐标轴ehr-web\src\views\rept\ReportAbstractRects.vue
注意:表格动态展示,需要在代码中进行computed监控数据的变化
<template>
<div>
<div class="myRectangleChartRow">
<div class="yLabelCol">
<div class="yLabelT">他评div>
<div class="yLabelT" v-for="(item, index) in frames" :key="index">{{ item }}div>
div>
<report-abstract-rectangle-chart
class="myRectangleChart"
:chartData="chartData"
:height="560"
:width="630"
:max="max"
:min="min"
>report-abstract-rectangle-chart>
div>
<div class="xLabelRow">
<div class="xLabel">自评div>
<div class="xLabel" v-for="(item, index) in frames" :key="index">{{ item }}div>
div>
div>
template>
<script>
import ReportAbstractRectangleChart from '@/views/rept/ReportAbstractRectangleChart'
export default {
name: 'ReportAbstractRects',
components: {
[ReportAbstractRectangleChart.name]: ReportAbstractRectangleChart
},
mounted() {},
data() {
return {
min: 0
}
},
// methods: {},
computed: {
// 坐标轴最大值
max() {
return this.maxRuleValue
},
// 循环坐标数据集
frames() {
const frames = []
const interval = this.max / 5
frames[0] = Math.round(interval * 100) / 100
frames[1] = Math.round(interval * 2 * 100) / 100
frames[2] = Math.round(interval * 3 * 100) / 100
frames[3] = Math.round(interval * 4 * 100) / 100
frames[4] = Math.round(this.max * 100) / 100
return frames
}
},
props: {
chartData: { type: Array, required: true },
maxRuleValue: { type: Number, required: true }
}
}
script>
<style lang="less" scoped>
.myRectangleChartRow {
display: inline-flex;
/* line-height: 30px; */
}
.yLabelCol {
width: 40px;
height: 558px;
display: flex;
flex-direction: column-reverse;
justify-content: space-between;
/* border: 2px solid transparent;
border-right-color: #096dd9; */
margin-top: -20px;
}
/* .yLabelCol:before{// 在最前面显示
content: "\2022";
} */
.yLabelT {
transform: rotate(-90deg);
}
.xLabelRow {
width: 623px;
display: inline-flex;
justify-content: space-between;
margin-left: 40px;
/* border: 2px solid transparent;
border-top-color: #096dd9; */
}
style>
画格子src\views\rept\ReportAbstractRectangleChart.vue
实现的原理就是,循环结果集,依据结果集的坐标数据,进行计算div的高度和偏移量实现
<template>
<div :style="{'height':height+'px','width':width+'px','position':'relative'}">
<div
v-for="(item, index) in chartData"
:key="index"
:style="{'width':getWidth(item),'height':getHeight(item),
'top':(max-item[3])/(max-min)*height+1+'px','left':(item[0]-min)/(max-min)*width+1+'px','background-color':item[5]}"
:class="['rectangle','rectangleImg'+index%5]"
@touchstart="gtouchstart"
@touchend="gtouchend"
>
<div class="rectangleText1">
<a-dropdown>
<a class="rectangleText1">{{ item[4] | areaTextEllipsis((item[1]-item[0])/(max-min)*width-8) }}a>
<a-menu slot="overlay">
<a-menu-item>{{ item[4] }}a-menu-item>
a-menu>
a-dropdown>
div>
<div v-if="item[6] && item[7] && item[7].length > 0">
<a-dropdown>
<a class="rectangleText2">{{ item[6] }}<span style="font-size:16px">项span>a>
<a-menu slot="overlay">
<a-menu-item>{{ item[7] | normArrayEllipsis }}a-menu-item>
a-menu>
a-dropdown>
div>
div>
div>
template>
<script>
export default {
name: 'ReportAbstractRectangleChart',
components: {
},
props: {
chartData: { type: Array, required: true },
height: { type: Number, required: true },
width: { type: Number, required: true },
max: { type: Number, required: true },
min: { type: Number, required: true }
},
data() {
return {
startX: 0,
startY: 0
// areaName: '',
// normArray: [],
// trCount: 0,
// visible: false
}
},
filters: {
normArrayEllipsis(normArray) {
var itemStr = ''
normArray.forEach((item, index) => {
itemStr = itemStr + item + ' | '
})
return itemStr.substring(0, itemStr.length - 2)
},
areaTextEllipsis(value, divWidth) {
// 文字整体所占宽度
var fontWidth = value.length * 16
// 如果div宽度大于整体宽度则原值返回,否则缩进...
if (divWidth >= fontWidth) {
return value
} else {
// 计算文字缩进偏移量
var offset = parseInt((fontWidth - divWidth) / 16) + 2
return value.substring(0, value.length - offset) + '...'
}
}
},
methods: {
gtouchstart(e) {
this.startY = e.changedTouches[0].pageY
this.startX = e.changedTouches[0].pageX
},
gtouchend(e) {
if (
this.startY === e.changedTouches[0].pageY &&
this.startX === e.changedTouches[0].pageX
) {
this.showDetailFunction()
} else {
}
},
showDetailFunction() {
this.$parent.showDetailFunction() // TODO:
},
// showNorms (title, normArray) {
// if (normArray.length === 0) {
// return
// }
// this.trCount = parseInt(normArray.length / 3) + 1
// this.areaName = title
// this.normArray = normArray
// this.visible = true
// },
handleCancel() {
this.visible = false
},
getWidth(item) {
if ((item[1] - item[0]) <= 0) {
return '4px'
}
const width = (item[1] - item[0]) / (this.max - this.min) * this.width - 8 + 'px'
return width
},
getHeight(item) {
if ((item[3] - item[2]) <= 0) {
return '4px'
}
const height = (item[3] - item[2]) / (this.max - this.min) * this.height - 8 + 'px'
return height
}
}
}
script>
<style lang="less" scoped>
.rectangle {
border-radius: 8px;
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.rectangleText1 {
color: white;
font-size: 16px;
font-weight: bold;
white-space: nowrap;
}
.rectangleText2 {
color: white;
font-size: 24px;
line-height: 1;
font-family: 'NeoSansStd-Light', 'Segoe UI', SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: lighter;
font-style: normal;
}
.rectangleImg5 {
transform: rotate(180deg);
position: absolute;
opacity: 0.05;
left: 10%;
top: 5%;
}
.normItem {
width: 90%;
margin: 20px 26px;
background-color: rgb(247, 248, 249);
}
// #normItemCount {
// cursor: pointer;
// }
style>
父页面
this.$router.push({
name: 'coverInfo',
query: {
setModuleId: poolItem.setModuleId,
templateId: this.templateId,
isExistSubjective: this.isExistSubjective,
modeId: this.modeId
}
})
coverInfo
<template>
<div style="background: #ffffff">
<a-spin :spinning="confirmLoading">
<div class="cover_title">
<p style="margin-left: 22px;">参数设置p>
div>
<a-form :form="form">
<a-form-item label="封面图片" :labelCol="labelCol" :wrapperCol="wrapperCol" style="left:9%;font-weight:bold">
<div class="cover_tip">
<p>(适用于PDF版本报告)p>
div>
<div>
<img v-if="coverInfo.imgUrl" :src="coverInfo.imgUrl" alt="cover" style="width:380px;height:213px;" />
div>
<div style="padding-left:148px;font-size:14px;font-weight:normal">
<a @click="$refs.coverModal.edit(coverInfo)">重新选择图片a>
div>
a-form-item>
<a-form-item
label="展示信息"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
style="left:9%;top:-20px;font-weight:bold"
>
<div style="padding-left: 140px;">
<div v-for="(item, index) in coverExts" :key="index" style="line-height:10px;margin-top:14px;">
<p>{{ item.showComment }}p>
div>
<div>
<a @click="editShowInfo" style="padding-left: 8px;font-size:14px;font-weight:normal">展示编辑字段a>
div>
div>
a-form-item>
<a-divider style="min-width: 10%;width: 35%;margin: 24px 425px;">a-divider>
<a-form-item :wrapperCol="{ span: 24 }" style="text-align: center">
<a-button htmlType="submit" icon="check-circle" type="primary" @click="this.handleSubmit">{{
this.global.BTN.SAVE
}}a-button>
<a-button style="margin-left: 8px" icon="close-circle" @click="this.handleCancel">{{
this.global.BTN.CANCEL
}}a-button>
a-form-item>
a-form>
a-spin>
<div>
<edit-show-info ref="editShowInfo" @ok="ok" />
<cover-modal ref="coverModal" @ok="coverOk">cover-modal>
div>
div>
template>
<script>
import { api } from '@/api/api'
import EditShowInfo from './EditShowInfo'
import CoverModal from './modules/CoverModal'
export default {
data() {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 7 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 7 }
},
form: this.$form.createForm(this),
confirmLoading: false,
fileList: [],
uploading: false,
loading: false,
imageUrl: '',
setModuleId: '',
coverInfo: {},
coverExts: [],
tempCoverExts: [],
templateId: 0,
isExistSubjective: 0,
modeId: 0
}
},
components: {
EditShowInfo,
CoverModal
},
created() {
this.setModuleId = this.$route.query.setModuleId
this.getCoverInfo()
this.templateId = this.$route.query.templateId
this.isExistSubjective = this.$route.query.isExistSubjective
this.modeId = this.$route.query.modeId
},
methods: {
handleSubmit() {
const {
form: { validateFields }
} = this
this.confirmLoading = true
validateFields((errors, values) => {
if (!errors) {
// const
api.post('/rept/cover/add', this.coverInfo).then(res => {
const cover = { id: this.coverInfo.id, setCoverExts: this.coverExts }
api.post('rept/coverExt/add', cover).then(res => {
this.$message.success(this.global.SAVE_SUCCESS)
this.confirmLoading = false
this.$router.replace({
name: 'evaluationTemplateSettings',
params: {
templateId: this.templateId,
modeId: this.modeId,
isExistSubjective: this.isExistSubjective,
tabKey: '4'
}
})
this.$router.go(-1)
})
})
} else {
this.$message.error(this.global.SAVE_FAIL)
this.confirmLoading = false
}
})
},
handleCancel() {
this.$router.replace({
name: 'evaluationTemplateSettings',
params: {
templateId: this.templateId,
modeId: this.modeId,
isExistSubjective: this.isExistSubjective,
tabKey: '4'
}
})
this.$router.go(-1)
},
editShowInfo() {
this.tempCoverExts = this.coverExts.slice(0, this.coverExts.length - 1)
const param = { coverInfo: this.coverInfo, coverExts: this.tempCoverExts }
console.log(param)
this.$refs.editShowInfo.edit(param)
},
ok(arr) {
this.coverExts = Object.assign([], arr)
},
getCoverInfo() {
api.get('/rept/cover/info/' + this.setModuleId).then(res => {
this.coverInfo = res
api.get('/rept/coverExt/list/' + res.id).then(res2 => {
this.coverExts = res2
})
})
},
coverOk(imgUrl) {
this.coverInfo.imgUrl = imgUrl
}
}
}
script>
<style scoped>
.cover_title {
font-size: 16px;
font-weight: bold;
text-align: left;
color: #333333;
margin-left: 54px;
padding-top: 30px;
}
.cover_tip {
background: #f2f5ff;
width: 369px;
/* font-size: 14px; */
text-align: center;
color: #666666;
margin-left: 5px;
}
style>
src\views\evaluation\setting\modules\CoverModal.vue
<template>
<a-modal
title="编辑封面"
:visible="visible"
:maskClosable="false"
:confirmLoading="confirmLoading"
:width="800"
:footer="null"
@cancel="cancelHandel">
<a-row>
<a-col :xs="24" :md="24" :style="{height: '400px'}">
<vue-cropper
ref="cropper"
:img="options.img"
:info="true"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
@realTime="realTime"
>
vue-cropper>
a-col>
a-row>
<br>
<a-row>
<a-col :lg="2" :md="2">
<a-upload name="file" :beforeUpload="beforeUpload" :showUploadList="false">
<a-button icon="upload">选择图片a-button>
a-upload>
a-col>
<a-col :lg="{span: 1, offset: 2}" :md="2">
<a-button icon="plus" @click="changeScale(1)"/>
a-col>
<a-col :lg="{span: 1, offset: 1}" :md="2">
<a-button icon="minus" @click="changeScale(-1)"/>
a-col>
<a-col :lg="{span: 1, offset: 1}" :md="2">
<a-button icon="undo" @click="rotateLeft"/>
a-col>
<a-col :lg="{span: 1, offset: 1}" :md="2">
<a-button icon="redo" @click="rotateRight"/>
a-col>
<a-col :lg="{span: 2, offset: 6}" :md="2">
<a-button type="primary" @click="finish('blob')" :disabled="isDisable">保存a-button>
a-col>
a-row>
a-modal>
template>
<script>
import { VueCropper } from 'vue-cropper'
import { ossAxios } from '@/utils/request'
export default {
components: {
VueCropper
},
data () {
return {
visible: false,
id: null,
confirmLoading: false,
fileList: [],
uploading: false,
options: {
// img: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
img: '',
autoCrop: true,
autoCropWidth: 600,
autoCropHeight: 400,
fixedBox: false
},
previews: {},
fileName: '',
isDisable: false
}
},
methods: {
edit (id) {
this.visible = true
this.id = id
this.isDisable = false
/* 获取原始头像 */
this.options.img = null
},
close () {
this.id = null
this.visible = false
},
cancelHandel () {
this.close()
},
changeScale (num) {
num = num || 1
this.$refs.cropper.changeScale(num)
},
rotateLeft () {
this.$refs.cropper.rotateLeft()
},
rotateRight () {
this.$refs.cropper.rotateRight()
},
beforeUpload (file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
if (!isJpgOrPng) {
this.$message.error('只能上传图片!')
return
}
this.fileName = file.name
const reader = new FileReader()
// 把Array Buffer转化为blob 如果是base64不需要
// 转化为base64
reader.readAsDataURL(file)
reader.onload = () => {
this.options.img = reader.result
}
// 转化为blob
// reader.readAsArrayBuffer(file)
return false
},
// 上传图片(点击上传按钮)
finish (type) {
if (!this.options.img) {
this.$message.error('请选择上传图片!')
return
}
this.isDisable = true
console.log('finish')
const formData = new FormData()
const _this = this
// 输出
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
const img = window.URL.createObjectURL(data)
this.model = true
this.modelSrc = img
formData.append('file', data, this.fileName)
ossAxios.post('', formData).then(res => {
const data = res.data
if (data.code === 200) {
_this.$message.success('上传成功')
_this.$emit('ok', '/files/' + data.data.fileId + '/preview/img')
_this.visible = false
} else {
this.isDisable = false
this.uploading = false
this.$message.error('上传失败')
}
})
})
} else {
this.$refs.cropper.getCropData((data) => {
this.model = true
this.modelSrc = data
})
}
},
okHandel () {
const vm = this
vm.confirmLoading = true
setTimeout(() => {
vm.confirmLoading = false
vm.close()
vm.$message.success('上传头像成功')
}, 2000)
},
realTime (data) {
this.previews = data
}
}
}
script>
<style lang="less" scoped>
.avatar-upload-preview {
position: absolute;
top: 50%;
transform: translate(50%, -50%);
width: 180px;
height: 180px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
style>
<router-link target="_blank" />
let href = this.$router.resolve({name: '', params: {}}) window.open(href.href, '_blank');
showPersonalReport(record) {
var releaseTime = record.releaseTime
if (releaseTime === undefined || releaseTime === null) {
releaseTime = parseInt((new Date()).getTime())
}
const routeData = this.$router.resolve({
name: 'PersonalReport',
params: {
reportDetailsId: record.detailsId,
reportReleaseTime: releaseTime,
searchType: '1'
}
})
window.open(routeData.href, '_blank')
},
<div style="width:305px;" :class="{'guide_desc_btn': guide.guideType !== '8'}">
<a class="guide_a" @click="$refs.type1.init('edit', guide, setModuleId)">编辑a>
<a class="guide_a" @click="delGuide(guide.guideId)">删除a>
<a v-show="index < guides.length - 1" class="guide_a" @click="moveDown(index)">下移a>
<a v-show="index > 0" class="guide_a" @click="moveUp(index)">上移a>
div>
<div v-if="guide.guideType !== '8'" style="width:100%; overflow: hidden; word-wrap:break-word;">
<a-textarea
style="overflow-y:hidden;border: none;resize: none;cursor: pointer;box-shadow: none;padding:0px 0px 0px 0px;font-weight:normal;font-family:PingFang SC Medium;font-size:14px;background: #f7f8f9;color:#666666"
readonly
:autosize="true"
:value="guide.guideDescribe"
/>
div>
<div v-else style="width:100%; overflow: hidden; word-wrap:break-word;">
<span v-html="changeCentent(guide.guideDescribe)">span>
div>
完整vue
<template>
<div class="parent_div">
<a-dropdown style="position: relative; top: 31px;width: 112px;z-index:1">
<a-button type="primary" icon="plus">新建内容<a-icon type="down"/>a-button>
<a-menu slot="overlay" @click="handleMenuClick">
<a-menu-item key="1"><a style="margin:0 auto;">系统预置模块a>a-menu-item>
<a-menu-item key="2"><a style="margin:0 auto;">自定义模块a>a-menu-item>
a-menu>
a-dropdown>
<a-tabs defaultActiveKey="1" :tabBarStyle="{ textAlign: 'right', borderBottom: 'set' }">
<a-tab-pane tab="中文" key="1">
<div style="margin-bottom: 20px;">
<img class="image_div" src="@/image/pen.png"/>
<span class="image_title">阅读指南参数设置span>
div>
<div class="guide" v-for="(guide, index) in guides" :key="index">
<div class="guide_title">
<span>{{ guide.guideTitle }}span>
div>
<div class="guide_desc">
<div style="display: flex;">
<div v-if="guide.guideType !== '8'" style="width:100%; overflow: hidden; word-wrap:break-word;">
<a-textarea
style="overflow-y:hidden;border: none;resize: none;cursor: pointer;box-shadow: none;padding:0px 0px 0px 0px;font-weight:normal;font-family:PingFang SC Medium;font-size:14px;background: #f7f8f9;color:#666666"
readonly
:autosize="true"
:value="guide.guideDescribe"
/>
div>
<div v-else style="width:100%; overflow: hidden; word-wrap:break-word;">
<span v-html="changeCentent(guide.guideDescribe)">span>
div>
<div style="width:305px;" :class="{'guide_desc_btn': guide.guideType !== '8'}">
<a class="guide_a" @click="$refs.type1.init('edit', guide, setModuleId)">编辑a>
<a class="guide_a" @click="delGuide(guide.guideId)">删除a>
<a v-show="index < guides.length - 1" class="guide_a" @click="moveDown(index)">下移a>
<a v-show="index > 0" class="guide_a" @click="moveUp(index)">上移a>
div>
div>
<div v-if="guide.guideType === '7' && guide.isShow && guide.isShow===1" style="width:75%;">
<a-table :rowKey="record => record.id" :columns="columns" :data-source="loadData" :pagination="false" bordered>a-table>
div>
div>
div>
a-tab-pane>
a-tabs>
<modify-guide ref="type1" @ok="handleOk">modify-guide>
<lib-guide ref="type2" @libGuide="libGuide">lib-guide>
div>
template>
<script>
import { api } from '@/api/api'
import ModifyGuide from '@/views/evaluation/setting/modules/ModifyGuide'
import LibGuide from '@/views/evaluation/setting/modules/LibGuide'
import VueUeditorWrap from 'vue-ueditor-wrap'
export default {
data() {
return {
setModuleId: 0,
guides: [],
guidesJP: [],
guidesUS: [],
loadData: [],
columns: [
{
dataIndex: 'cell1',
title: '评价角色'
},
{
dataIndex: 'cell2',
title: '发送评价邀请数'
},
{
dataIndex: 'cell3',
title: '有效作答数'
},
{
dataIndex: 'cell4',
title: '有效作答占比'
}
]
}
},
created() {
this.setModuleId = this.$route.query.setModuleId
this.initMethod()
this.loadData = [
{ 'id': 1, 'cell1': '自己', 'cell2': '', 'cell3': '', 'cell4': '' },
{ 'id': 2, 'cell1': '上级', 'cell2': '', 'cell3': '', 'cell4': '' },
{ 'id': 3, 'cell1': '同级', 'cell2': '', 'cell3': '', 'cell4': '' },
{ 'id': 4, 'cell1': '下级', 'cell2': '', 'cell3': '', 'cell4': '' }
]
},
methods: {
initMethod() {
// HrReptSetGuideController
api.get('/rept/guides/' + this.setModuleId).then(res => {
if (!res) {
this.guides = []
this.guidesJP = []
this.guidesUS = []
} else {
this.guides = res['zh-CN']
this.guidesJP = res['ja-JP']
this.guidesUS = res['en-US']
}
})
},
// 替换换行符
changeCentent(content) {
if (!content) {
return content
}
return content.replace(/\n/g, '
')
},
// 向上移动
moveUp(index) {
const guide = this.guides[index]
const nestGuide = this.guides[index - 1]
// /moveDown/{guideId}/{guideOrder}/{nextGuideId}/{nextGuideOrder}
api.put('/rept/guides/moveUp/' + guide.guideId + '/' + guide.guideOrder + '/' +
nestGuide.guideId + '/' + nestGuide.guideOrder + '/' + this.setModuleId).then(res => {
this.initMethod()
})
},
// 向下移动
moveDown(index) {
const guide = this.guides[index]
const nestGuide = this.guides[index + 1]
api.put('/rept/guides/moveDown/' + guide.guideId + '/' + guide.guideOrder + '/' +
nestGuide.guideId + '/' + nestGuide.guideOrder + '/' + this.setModuleId).then(res => {
this.initMethod()
})
},
// 删除操作
delGuide(guideId) {
this.$confirm({
title: this.global.PROMPT,
content: this.global.DEL_CONFIRM,
okText: this.global.BTN.OK,
cancelText: this.global.BTN.CANCEL,
onOk: () => {
api.delete('/rept/guides/delete/' + guideId + '/' + this.setModuleId).then(res => {
this.$message.success(this.global.DEL_SUCCESS)
this.initMethod()
})
},
onCancel() {}
})
},
// 点击菜单
handleMenuClick(data) {
if (data.key === '1') { // 系统模板
this.$refs.type2.init(this.setModuleId)
} else {
this.$refs.type1.init('add', null, this.setModuleId)
}
},
// 子页面回调方法
handleOk () {
this.initMethod()
},
// 系统调用模板下一步返回参数
libGuide (libguide) {
this.$refs.type1.init('libEdit', libguide, this.setModuleId)
}
},
components: {
ModifyGuide,
LibGuide,
VueUeditorWrap
}
}
script>
<style scoped>
* {
padding: 0;
margin:0;
}
.parent_div {
width: 98%;
position: relative;
left: 1%;
top: -13px;
}
.parent_div >>> .ant-tabs-bar {
border-bottom: 1px solid #fff;
}
.image_div {
width: 23px;
height: 23px;
}
.image_title {
font-size: 16px;
font-weight: bold;
color: #333333;
position: relative;
left: 10px;
top: 4px;
}
.guide{
border-left: 4px solid #E9E9EB;
padding: 20px 14px 20px 32px;
background-color: #F7F8F9;
margin-bottom: 8px;
display: flex;
}
.guide_title{
font-size: 15px;
color: #666666;
font-weight: bold;
width:200px;
}
.guide_desc{
width:100%;
overflow: hidden;
}
.guide_a{
margin-left: 25px;
font-size: 15px;
color: #3B8FDA;
}
.parent_div a:hover{
cursor:pointer
}
.guide_desc_btn{
display: flex;
align-items: center;
}
style>
实现如下功能:
// 执行公式,计算分数:如4.5+2 => 6.5
ArithUtils.java
package com.neusoft.ehr.eval.util;
/**
* 精确计算工具类
*
* @author shao.hw
* @since 2020-04-18
*/
public class ArithUtils {
// 默认除法运算精度
private static final int DEF_DIV_SCALE = 16;
// 这个类不能实例化
private ArithUtils() {
}
/**
* 提供精确的加法运算。
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
public static double add(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.add(b2).doubleValue();
}
/**
* 提供精确的减法运算。
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
public static double sub(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的乘法运算。
*
* @param v1
* 被乘数
* @param v2
* 乘数
* @return 两个参数的积
*/
public static double mul(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
public static double mul(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.multiply(b2).doubleValue();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
*
* @param v1
* 被除数
* @param v2
* 除数
* @return 两个参数的商
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}
public static double div(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理。
*
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
public static double round(String v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(v);
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
CalculatorUtils.java
package com.neusoft.ehr.eval.util;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Stack;
/**
* 算数表达式求值
* 直接调用Calculator的类方法conversion()
* 传入算数表达式,将返回一个BigDecimal结果,保留四位小数
* 如果计算过程错误,将返回 -1
*
* @author shao.hw
* @since 2020-04-18
*/
public class CalculatorUtils {
private Stack<String> postfixStack = new Stack<String>();// 后缀式栈
private Stack<Character> opStack = new Stack<Character>();// 运算符栈
private int[] operatPriority = new int[] { 0, 3, 2, 1, -1, 1, 0, 2 };// 运用运算符ASCII码-40做索引的运算符优先级
public static BigDecimal conversion(String expression) {
BigDecimal result = BigDecimal.ZERO;
CalculatorUtils cal = new CalculatorUtils();
try {
result = cal.calculate(expression);
} catch (Exception e) {
// e.printStackTrace();
// 运算错误返回-1
return BigDecimal.valueOf(-1);
}
return result.setScale(4,BigDecimal.ROUND_HALF_UP);
}
/**
* 按照给定的表达式计算
*
* @param expression
* 要计算的表达式例如:5+12*(3+5)/7
* @return
*/
public BigDecimal calculate(String expression) {
Stack<String> resultStack = new Stack<String>();
prepare(expression);
Collections.reverse(postfixStack);// 将后缀式栈反转
String firstValue, secondValue, currentValue;// 参与计算的第一个值,第二个值和算术运算符
while (!postfixStack.isEmpty()) {
currentValue = postfixStack.pop();
if (!isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中
currentValue = currentValue.replace("~", "-");
resultStack.push(currentValue);
} else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
secondValue = resultStack.pop();
firstValue = resultStack.pop();
// 将负数标记符改为负号
firstValue = firstValue.replace("~", "-");
secondValue = secondValue.replace("~", "-");
String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
resultStack.push(tempResult);
}
}
return BigDecimal.valueOf(Double.valueOf(resultStack.pop()));
}
/**
* 数据准备阶段将表达式转换成为后缀式栈
*
* @param expression
*/
private void prepare(String expression) {
opStack.push(',');// 运算符放入栈底元素逗号,此符号优先级最低
char[] arr = expression.toCharArray();
int currentIndex = 0;// 当前字符的位置
int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
char currentOp, peekOp;// 当前操作符和栈顶操作符
for (int i = 0; i < arr.length; i++) {
currentOp = arr[i];
if (isOperator(currentOp)) {// 如果当前字符是运算符
if (count > 0) {
postfixStack.push(new String(arr, currentIndex, count));// 取两个运算符之间的数字
}
peekOp = opStack.peek();
if (currentOp == ')') {// 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
while (opStack.peek() != '(') {
postfixStack.push(String.valueOf(opStack.pop()));
}
opStack.pop();
} else {
while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
postfixStack.push(String.valueOf(opStack.pop()));
peekOp = opStack.peek();
}
opStack.push(currentOp);
}
count = 0;
currentIndex = i + 1;
} else {
count++;
}
}
if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
postfixStack.push(new String(arr, currentIndex, count));
}
while (opStack.peek() != ',') {
postfixStack.push(String.valueOf(opStack.pop()));// 将操作符栈中的剩余的元素添加到后缀式栈中
}
}
/**
* 判断是否为算术符号
*
* @param c
* @return
*/
private boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}
/**
* 利用ASCII码-40做下标去算术符号优先级
*
* @param cur
* @param peek
* @return
*/
public boolean compare(char cur, char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
boolean result = false;
if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
result = true;
}
return result;
}
/**
* 按照给定的算术运算符做计算
*
* @param firstValue
* @param secondValue
* @param currentOp
* @return
*/
private String calculate(String firstValue, String secondValue, char currentOp) {
String result = "";
switch (currentOp) {
case '+':
result = String.valueOf(ArithUtils.add(firstValue, secondValue));
break;
case '-':
result = String.valueOf(ArithUtils.sub(firstValue, secondValue));
break;
case '*':
result = String.valueOf(ArithUtils.mul(firstValue, secondValue));
break;
case '/':
result = String.valueOf(ArithUtils.div(firstValue, secondValue));
break;
}
return result;
}
}
// 执行公式,计算分数:如4.5+2 => 6.5
BigDecimal realityScore = CalculatorUtils.conversion(calcFormula);
if(BigDecimal.valueOf(-1).compareTo(realityScore) == 0) {
log.error("指标计算出错:"+ map.getKey() + ";normId:"+normVo.getNormId()+";计算公式:"+normVo.getCalcFormula() +"calcFormula:"+ calcFormula + ";realityScore:"+realityScore);
}
直接替换系统属性值
StrSubstitutor.replaceSystemProperties(
"You are running with java.version = ${java.version} and os.name = ${os.name}.");
使用Map替换字符串中的占位符
Map valuesMap = HashMap();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StrSubstitutor sub = new StrSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);
// resolvedString的結果:The quick brown fox jumped over the lazy dog.
StrSubstitutor会递归地替换变量,比如
Map<String, Object> params = Maps.newHashMap();
params.put("name", "${x}");
params.put("x", "y");
StrSubstitutor strSubstitutor = new StrSubstitutor(params);
String hello2 = "${name}";
System.out.println(strSubstitutor.replace(hello2));
// 最后会输出:y
有时变量内还嵌套其它变量,这个StrSubstitutor也是支持的,要调用setEnableSubstitutionInVariables
Map<String, Object> params = Maps.newHashMap();
params.put("jre-1.8", "java-version-1.8");
params.put("java.specification.version", "1.8");
StrSubstitutor strSubstitutor = new StrSubstitutor(params);
strSubstitutor.setEnableSubstitutionInVariables(true);
System.out.println(strSubstitutor.replace("${jre-${java.specification.version}}"));
// java-version-1.83,自动生成代码配置文件
匹配数字:
AND t1.score REGEXP '^[0-9]*.?[0-9]$'
@MapKey("sumLogic")
Map<Integer, Map<String, Integer>> getSumLogicMap(@Param("params") Map<String, Object> basicInfo);
xml
<select id="getSumLogicMap" resultType="java.util.HashMap">
SELECT
t.logic_type sumLogic,
t.mode_type sumMode
FROM
hr_eval_activity_calc t
WHERE
t.is_deleted = 0
AND t.template_id = #{params.templateId}
AND t.rule_id = #{params.ruleId}
AND t.activity_id = #{params.activityId}
AND t.logic_type in (0, 1)
select>
<if test="param.dimension != null and param.dimension != ''">
and t.dimension_id = #{param.dimension}
if>
<include refid="selectSql"/>
<when test="type!= null and type=='module'"><choose>
<when test="type!= null and type=='template'">
union all
select '评估模板' title, 'templateName' dataIndex from dual
when>
<when test="type!= null and type=='module'">
union all
select '评估模板' title, 'templateName' dataIndex from dual
union all
select '评估模块' title, 'moduleName' dataIndex from dual
when>
<when test="type!= null and type=='dimension'">
union all
select '评估模板' title, 'templateName' dataIndex from dual
union all
select '评估模块' title, 'moduleName' dataIndex from dual
union all
select '评价维度' title, 'dimensionName' dataIndex from dual
when>
<otherwise>
union all
select '评估模板' title, 'templateName' dataIndex from dual
union all
select '评估模块' title, 'moduleName' dataIndex from dual
union all
select '评价维度' title, 'dimensionName' dataIndex from dual
union all
select '指标名' title, 'normName' dataIndex from dual
otherwise>
choose>
convert(t.score_tp,decimal(10,1)) scoreTp,
<foreach collection="param.leaderLevels" item="item" open="and appraisee.leader_level in (" close=")" separator=",">
#{item}
foreach>
concat('ACT_', a.activity_id, '_', substring_index(a.assessor_mail,'@',1)) redisKey,
<resultMap id="EvalConstVO" type="com.neusoft.ehr.eval.vo.HrEvalConstVO">
<id column="id" property="id"/>
<result column="templateId" property="templateId"/>
<result column="constId" property="constId"/>
<result column="constType" property="constType"/>
<result column="constNameZH" property="constNameZH"/>
<result column="constNameEN" property="constNameEN"/>
<result column="constNameJP" property="constNameJP"/>
<result column="constDescZH" property="constDescZH"/>
<result column="constDescEN" property="constDescEN"/>
<result column="constDescJP" property="constDescJP"/>
<result column="arithLogic" property="arithLogic"/>
<result column="setColor" property="setColor"/>
<result column="showOrderHome" property="showOrderHome" />
<collection property="constRules" ofType="com.neusoft.ehr.eval.po.HrReptSetConstRulePO">
<result column="ruleLeft" property="ruleLeft"/>
<result column="ruleRight" property="ruleRight"/>
<result column="computeSign" property="computeSign"/>
<result column="ruleValue" property="ruleValue"/>
<result column="showOrder" property="showOrder"/>
collection>
resultMap>
<select id="getConst" resultMap="EvalConstVO">select>
HrEvalConstVO
public class HrEvalConstVO {
@ApiModelProperty(value = "model主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@ApiModelProperty(value = "模板业务主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long templateId;
@ApiModelProperty(value = "报告常量模型业务主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long constId;
@ApiModelProperty(value = "报告常量模型")
private String constType;
@ApiModelProperty(value = "名称中文")
private String constNameZH;
@ApiModelProperty(value = "名称英文")
private String constNameEN;
@ApiModelProperty(value = "名称日文")
private String constNameJP;
@ApiModelProperty(value = "说明中文")
private String constDescZH;
@ApiModelProperty(value = "说明英文")
private String constDescEN;
@ApiModelProperty(value = "说明日文")
private String constDescJP;
@ApiModelProperty(value = "规则间运算逻辑(常用代码:code_arith_logic)")
private String arithLogic;
@ApiModelProperty(value = "配色")
private String setColor;
@ApiModelProperty(value = "显示顺序")
private Integer showOrderHome;
@ApiModelProperty(value = "计算规则部分")
List<HrReptSetConstRulePO> constRules = new ArrayList<>();
}
resultTotalDTOMap.forEach((k, v) -> {
});
evalCalculateScorePOList.forEach(evalCalculateScorePO -> {
});
String string = "2我们1";
String tempStr = "";
String targetStr = "";
for(int i=0; i<string.length(); i++) {
String s = String.valueOf(string.charAt(i));
if(s.matches(regex)
|| (i>0 && s.matches("[0-9]") && String.valueOf(string.charAt(i-1)).matches(regex))
|| (i>0 && s.matches(regex) && String.valueOf(string.charAt(i-1)).matches("[0-9]") )) {
tempStr = tempStr + string.charAt(i);
if (i == string.length() -1) {
targetStr = targetStr + "${" + tempStr + "}";
}
continue;
}
if (!StringUtils.isEmpty(tempStr)) {
targetStr = targetStr + "${" + tempStr + "}" + string.charAt(i);
} else if (i<string.length()-1 && s.matches("[0-9]") && String.valueOf(string.charAt(i+1)).matches(regex) ) {
// 2正念
tempStr = s;
continue;
}else {
targetStr = targetStr + string.charAt(i);
}
tempStr = "";
}
System.out.println(targetStr);
Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("正念", "(1+1)");
valuesMap.put("我们", "(1+2)");
StrSubstitutor sub = new StrSubstitutor(valuesMap);
String calcFormula = sub.replace(targetStr);
System.out.println("----------" + calcFormula);
// 执行公式,计算分数:如4.5+2 => 6.5
BigDecimal realityScore = CalculatorUtils.conversion(calcFormula);
System.out.println("realityScore:" + realityScore);
if(BigDecimal.valueOf(-1).compareTo(realityScore) == 0) {
System.out.println("-------------->");
}
SELECT @i:=0;
UPDATE hr_rept_set_const_model t set t.show_order = @i:=@i+1 where t.template_id = 130 and t.is_deleted = 0 and t.const_type=4
// 查询
LambdaQueryWrapper<HrReptSetConstModelPO> queryAllWrapper = new LambdaQueryWrapper<>();
queryAllWrapper.eq(HrReptSetConstModelPO::getTemplateId, constUpdateVo.getTemplateId());
queryAllWrapper.eq(HrReptSetConstModelPO::getConstType, constUpdateVo.getConstType());
queryAllWrapper.orderByDesc(HrReptSetConstModelPO::getShowOrder);
List<HrReptSetConstModelPO> showOrders = this.getEhrBaseMapper().selectList(queryAllWrapper);
showOrder = showOrders.size() > CommonConstants.ZERO ?
showOrders.get(0).getShowOrder() + CommonConstants.ONE : CommonConstants.ONE;
// 更新
public String move(String direction, Long guideId, Integer guideOrder, Long nextGuideId, Integer nextGuideOrder) {
// 移动操作将当前guideId的guideOrder与nextGuideId的nextGuideOrder互换
// 操作当前条数据
HrReptSetGuidePO po = new HrReptSetGuidePO();
po.setGuideOrder(nextGuideOrder);
LambdaUpdateWrapper<HrReptSetGuidePO> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(HrReptSetGuidePO::getGuideId, guideId);
this.update(po, updateWrapper);
// 操作下一条数据
po.setGuideOrder(guideOrder);
LambdaUpdateWrapper<HrReptSetGuidePO> nextUpdateWrapper = new LambdaUpdateWrapper<>();
nextUpdateWrapper.eq(HrReptSetGuidePO::getGuideId, nextGuideId);
this.update(po, nextUpdateWrapper);
return "OK";
}
// 删除
public String deleteConstModel(Long constId) {
LambdaQueryWrapper<HrReptSetConstModelPO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(HrReptSetConstModelPO::getConstId,constId);
this.getEhrBaseMapper().delete(queryWrapper);
return "success";
}
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired), access = AccessLevel.PUBLIC)
private final HrReptSetConstModelService cms;
@GetMapping(value = "/getGridData/{templateId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public R<Map<String, List<HrEvalConstHomeVO>>> getGridData(@PathVariable Long templateId){}
@PostMapping(value = "/addOrUpdateConst", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public BaseResponse addOrUpdateConst(@RequestBody HrEvalConstVO constUpdateVo) {}
// 多个元素排序
// 将集合数据按照计算规则和显示顺序进行升序排序
Collections.sort(values, (s1, s2) -> {
if (Integer.valueOf(s1.getRuleLeft()) - Integer.valueOf(s2.getRuleLeft()) >= 0) {
if (s1.getShowOrder() - s2.getShowOrder() >= 0) {
return 1;
} else {
return -1;
}
} else {
return -1;
}
});
// 单个元素排序
Collections.sort(list3, (s1,s2) -> (s1.getShowOrderHome() - s2.getShowOrderHome()));
区间校验推荐使用guava来实现简单,如下方式自己手动实现方式
@Override
public String checkRepeat(HrReptConstCheckVO checkVO) {
log.info("hrReptConstCheckVO:" + ToStringBuilder.reflectionToString(checkVO));
List<HrReptConstCheckVO> results = this.baseMapper.getRuleValueCount(checkVO);
List<HrReptConstCheckVO> newResults = new ArrayList<>();
for (int i=0; i<results.size(); i = i + 2) {
HrReptConstCheckVO newResult = new HrReptConstCheckVO();
newResult.setConstId(results.get(i).getConstId());
// 当前条设置左边分数和计算符号
newResult.setLeftRuleValue(results.get(i).getRuleValue());
newResult.setLeftComputeSign(results.get(i).getComputeSign());
// 下一条设置右边分数和计算符号
newResult.setRightRuleValue(results.get(i+1).getRuleValue());
newResult.setRightComputeSign(results.get(i+1).getComputeSign());
newResults.add(newResult);
}
Integer leftRuleValue, rightRuleValue;
String leftComputeSign, rightComputeSign;
if (newResults != null && newResults.size() > 0) {
for (HrReptConstCheckVO result : newResults) {
if (checkVO.getConstId().equals(result.getConstId())) {
continue;
}
leftRuleValue = result.getLeftRuleValue();
rightRuleValue = result.getRightRuleValue();
leftComputeSign = result.getLeftComputeSign();
rightComputeSign = result.getRightComputeSign();
// ComputeSign: 2:<; 3:≤
if ("2".equals(leftComputeSign) && "2".equals(rightComputeSign)) {
// 10 < 得分 < 20 -> 合法:左边>=20 || 右边<=10
if (!(checkVO.getLeftRuleValue() >= rightRuleValue || checkVO.getRightRuleValue() <= leftRuleValue)) {
return "NG";
}
} else if ("2".equals(leftComputeSign) && "3".equals(rightComputeSign)) {
// 10 < 得分 <= 20 -> 合法:左边>20 || 右边<=10 || (左边值=20 && 左边符号<)
if (!(checkVO.getLeftRuleValue() > rightRuleValue || checkVO.getRightRuleValue() <= leftRuleValue
|| (checkVO.getLeftRuleValue() == rightRuleValue && "2".equals(checkVO.getLeftComputeSign())))) {
return "NG";
}
} else if ("3".equals(leftComputeSign) && "2".equals(rightComputeSign)) {
// 10 <= 得分 < 20 -> 合法:左边>=20 || 右边<10 || (右边值=10 && 右边符号<)
if (!(checkVO.getLeftRuleValue() >= rightRuleValue || checkVO.getRightRuleValue() < leftRuleValue
|| (checkVO.getRightRuleValue() == leftRuleValue && "2".equals(checkVO.getRightComputeSign())))) {
return "NG";
}
} else {
// 10 <= 得分 <= 20 -> 合法:左边>20 || 右边<10 || (左边值=20 && 左边符号<) || (右边值=10 && 右边符号<)
if (!(checkVO.getLeftRuleValue() > rightRuleValue || checkVO.getRightRuleValue() < leftRuleValue
|| (checkVO.getLeftRuleValue() == rightRuleValue && "2".equals(checkVO.getLeftComputeSign()))
|| (checkVO.getRightRuleValue() == leftRuleValue && "2".equals(checkVO.getRightComputeSign()))
)) {
return "NG";
}
}
}
}
return "OK";
}
@JsonSerialize(using = ToStringSerializer.class)
private Long constId;
参照IdWorker
package com.neusoft.ehr.eval.util;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class IdWorker {
private static final Pattern PATTERN_LONG_ID = Pattern.compile("^([0-9]{15})([0-9a-f]{32})([0-9a-f]{3})$");
private static final Pattern PATTERN_HOSTNAME = Pattern.compile("^.*\\D+([0-9]+)$");
private static final long OFFSET = LocalDate.of(2000, 1, 1).atStartOfDay(ZoneId.of("Z")).toEpochSecond();
private static final long MAX_NEXT = 0b11111_11111111_111L;
private static final long SHARD_ID = getServerIdAsLong();
private static long offset = 0;
private static long lastEpoch = 0;
public static long getNextId() {
return nextId(System.currentTimeMillis() / 1000);
}
private static synchronized long nextId(long epochSecond) {
if (epochSecond < lastEpoch) {
epochSecond = lastEpoch;
}
if (lastEpoch != epochSecond) {
lastEpoch = epochSecond;
reset();
}
offset++;
long next = offset & MAX_NEXT;
if (next == 0) {
return nextId(epochSecond + 1);
}
return generateId(epochSecond, next, SHARD_ID);
}
private static void reset() {
offset = 0;
}
private static long generateId(long epochSecond, long next, long shardId) {
return ((epochSecond - OFFSET) << 21) | (next << 5) | shardId;
}
private static long getServerIdAsLong() {
try {
String hostname = InetAddress.getLocalHost().getHostName();
Matcher matcher = PATTERN_HOSTNAME.matcher(hostname);
if (matcher.matches()) {
long n = Long.parseLong(matcher.group(1));
if (n >= 0 && n < 8) {
return n;
}
}
} catch (UnknownHostException e) {
}
return 0;
}
public static void main(String[] args) {
System.out.println(getNextId());
}
}