Parcourir la source

Merge branch '长阳分支中职' of http://123.57.209.16:3000/bjquanjiang/DigitalScholl into 长阳分支中职

临城职教中职
ndbs il y a 2 ans
Parent
révision
72b183d3e2
13 fichiers modifiés avec 683 ajouts et 588 suppressions
  1. +1
    -2
      Learun.Framework.Ultimate V7/Learun.Application.WebApi/Modules/AnnexesApiWx.cs
  2. +306
    -270
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/common/customform.js
  3. +0
    -1
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/common/custompage.js
  4. +13
    -4
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/common/mixins.js
  5. +2
    -2
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/config.js
  6. +1
    -1
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/msg.vue
  7. +1
    -1
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/msg/chat.vue
  8. +1
    -1
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/my.vue
  9. +1
    -1
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/my/info.vue
  10. +1
    -1
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/my/qrcode.vue
  11. +0
    -5
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/myflow/single.vue
  12. +5
    -2
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/releasetask/single.vue
  13. +351
    -297
      Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/workflow.js

+ 1
- 2
Learun.Framework.Ultimate V7/Learun.Application.WebApi/Modules/AnnexesApiWx.cs Voir le fichier

@@ -40,8 +40,7 @@ namespace Learun.Application.WebApi.Modules
public Response WxUpload(dynamic _)
{
var files = (List<HttpFile>)this.Context.Request.Files;
//var folderId = this.GetReqData();
string folderId = Guid.NewGuid().ToString();
string folderId = Request.Form["folderId"];
string filePath = Config.GetValue("AnnexesFile");
string uploadDate = DateTime.Now.ToString("yyyyMMdd");
string fileEextension = Path.GetExtension(files[0].Name);


+ 306
- 270
Learun.Framework.Ultimate V7/LearunApp-2.2.0/common/customform.js Voir le fichier

@@ -24,274 +24,310 @@ import moment from 'moment'
*/

export default {
methods: {
/**
* 获取一个 scheme 表单项的源数据 (加载表单时使用)
* 参数: 单个 schemeItem
*
* radio、select、checkbox、layer 这四种表单项,需要加载额外的选单数据
* 选单数据有两种获取方式:
* 1、来自数据字典:
* 数据字典在 this.GET_GLOBAL('dataDictionary')
* 表单使用的字段在 schemeItem.itemCode
* 选单数据中的 text 字段作为显示, value 字段作为值
*
* 2、来自数据源:
* 将 schemeItem.dataSourceId 按符号「,」逗号分割为数组,分割为: [code, displayField, valueField]
* 数据源需要请求 API 来获取,请求需要带上数据源的编号 code
* displayField、valueField 分别为展示字段和值绑定字段
*
* 选单数据有两种格式:
* 1、对于 radio、select、checkbox 来说:
* 只需要一个数组,数组形如: [{ text: '选项文字', value: '选项值' }, ...]
* 将获取的数据绑定到组件的 range 属性上即可
* 全局数据中默认是对象形式,使用 Object.values() 转化即可
*
* 2、对于 layer 来说:
* 返回一个对象,形如 { source, layerData, selfField }
* source: 为弹层中列出的数据,是一个数组
* layerData: 需要在弹层窗口中展示的字段及标题文字,形如: [{ name:'要展示的字段名', label:'标题文字' }]
* selfField: 该表单值绑定哪个字段,默认为绑定到自身的字段
*/
async getSourceData(schemeItem) {
if (['radio', 'select', 'checkbox'].includes(schemeItem.type)) {
// radio select checkbox 三种情况
if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) {
// dataSource 为 0,使用 clientData
return Object
.values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode])
.map(t => ({ value: t.value, text: t.text }))

} else {
// dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段
const [code, displayField = schemeItem.showField, valueField = schemeItem.saveField] = schemeItem.dataSourceId
.split(',')
const sourceData = await this.FETCH_DATASOURCE(code)
if (!sourceData) { return [] }

return sourceData.data.map(t => ({ text: t[displayField], value: t[valueField] }))
}

} else if (['layer'].includes(schemeItem.type)) {
// layer 需要更多属性
if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) {
// dataSource 为 0,使用 clientData
// clientData 对象转数组后,隐含 key:item.text 和 value:item.value 的关系
const [keyItem, valueItem] = schemeItem.layerData
const source = Object
.values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode])
.map(t => ({ value: t.value, text: t.text }))

return {
source,
layerData: [
{ name: 'text', label: keyItem.label || '', value: keyItem.value || '' },
{ name: 'value', label: valueItem.label || '', value: valueItem.value || '' }
]
}
} else {
// dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段
const [code] = schemeItem.dataSourceId.split(',')
const sourceData = await this.FETCH_DATASOURCE(code)
if (!sourceData) { return [] }

const source = sourceData.data

return { source, layerData: schemeItem.layerData.filter(t => (!t.hide) && (t.value || t.label)) }
}
}

return []
},

/**
* 获取一个 scheme 表单项的默认值 (用户新建表单时使用,或是编辑草稿)
* 参数: 单个 schemeItem , { processId }
*
* 每种类别的表单项分别获取的默认值:
*
* currentInfo: 根据类别取当前用户/部门/公司/时间日期
* datetime: 根据 dfValue 字段表示昨天/今天/明天,格式化为字符串
* radio、select: 有 dfValue 则使用,否则取第一条
* checkbox: 有 dfValue 则使用,否则为空数组
* encode: 根据 rulecode 请求表单编码
* upload: 空数组
* guid: 赋值第二个参数中的 processId,但是如果在子表格中,赋空字符串
* girdtable: 递归所有表格项 scheme 依次为它们生成默认值
* datetimerange: 字符串 0
*/
async getDefaultData(item, prop) {
const { processId } = prop
switch (item.type) {
case 'currentInfo':
switch (item.dataType) {
case 'user':
return this.GET_GLOBAL('loginUser').userId
case 'department':
return this.GET_GLOBAL('loginUser').departmentId
case 'company':
return this.GET_GLOBAL('loginUser').companyId
case 'time':
return moment().format('YYYY-MM-DD HH:mm:ss')
default:
return ''
}

case 'datetime':
const datetimeFormat = item.table ?
(Number(item.dateformat) === 0 ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss') :
(item.datetime === 'datetime' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
const today = moment()
const dfDatetime = [
today.subtract(1, 'day'),
today,
today.add(1, 'day')
][Number(item.dfvalue)] || today

return dfDatetime.format(datetimeFormat) || ''

case 'radio':
case 'select':
const radioItem = item.__sourceData__.find(t => t.value === item.dfvalue) || item.__sourceData__[0]
return item.type === 'radio' ? radioItem.value : ''

case 'checkbox':
if (!item.dfvalue) {
return []
}
return item.dfvalue.split(',').filter(t => item.__sourceData__.find(s => s.value === t))

case 'encode':
const result = await this.FETCH_ENCODE(item.rulecode)
return result

case 'upload':
return []

case 'guid':
return item.table ? processId : ''

case 'girdtable':
const tableItemObj = {}
for (const fieldItem of item.fieldsData) {
tableItemObj[fieldItem.field] = await this.getDefaultData(fieldItem, prop)
}
return this.COPY(tableItemObj)

case 'datetimerange':
return '0'

default:
return item.dfvalue || ''
}
},

/**
* 将单条 formData 值转化为 formValue 值 (拉取表单数据时使用)
* 参数: 单个 schemeItem , 数据值
*
* 具体执行逻辑:
* radio、select: 剔除无效值
* checkbox: 分割成数组并剔除无效值
* upload: 分割成数组,拉取其中所有文件的信息
* datetime: 按照时间日期格式进行格式化字符串
* 其他类型: 保留原值
*/
async convertToFormValue(item, val) {
switch (item.type) {
case 'upload':
if (!val) { return [] }
const uidList = val.split(',')
const fileList = []

for (const uid of uidList || []) {
const fileInfo = await this.FETCH_FILEINFO(uid)
if (!fileInfo) { continue }

const fileType = fileInfo.F_FileType
const fileSize = fileInfo.F_FileSize

const path = this.API + '/annexes/wxdown?' + this.URL_QUERY(uid, true)

fileList.push({ path, type: fileType, uid, size: fileSize })
}
return fileList

case 'select':
case 'radio':
if (!val || !item.__sourceData__.map(t => t.value).includes(val)) {
return ''
}
return val

case 'checkbox':
const validValue = item.__sourceData__.map(t => t.value)
const checkboxVal = val.split(',') || []
return checkboxVal.filter(t => validValue.includes(t))

case 'datetime':
if (!val) {
return ''
}
return moment(val).format(
Number(item.dateformat) === 0 || item.datetime === 'date' ?
'YYYY-MM-DD' :
'YYYY-MM-DD HH:mm:ss'
)

default:
return val || ''
}
},

/**
* 将一个 formValue 值转化为 post 提交值(提交表单数据时使用)
* 参数: 单个 schemeItem , 表单项值 , 所有 formValue , scheme
*
* 具体执行逻辑:
* checkbox: 将数组使用符号「,」逗号拼接成字符串
* datetimerange: 获取开始日期、结束日期,计算差值天数并保留整数
* datetime: 格式化为完整时间日期字符串
* upload: 依次上传文件,将返回的文件 ID 使用符号「,」逗号拼接成字符串
* 其他类型: 保留原值
*/
async convertToPostData(item, val, formValue, scheme) {
switch (item.type) {
case 'checkbox':
return val ? val.join(',') : ''

case 'datetimerange':
const startTime = get(formValue, scheme.find(t => t.id === item.startTime).__valuePath__, null)
const endTime = get(formValue, scheme.find(t => t.id === item.endTime).__valuePath__, null)
if (!startTime || !endTime || moment(endTime).isBefore(startTime)) {
return ''
} else {
return moment.duration(moment(endTime).diff(moment(startTime))).asDays().toFixed(0)
}

case 'datetime':
return val ? moment(val).format('YYYY-MM-DD HH:mm:ss') : ''

case 'upload':
const uploadUid = []
for (const item of val) {
if (item.uid) {
uploadUid.push(item.uid)
continue
}
const fileId = await this.HTTP_UPLOAD(item.path||item)
if (fileId) {
uploadUid.push(fileId)
}
}

return uploadUid.join(',')

default:
return val || ''
}
}
}
methods: {
/**
* 获取一个 scheme 表单项的源数据 (加载表单时使用)
* 参数: 单个 schemeItem
*
* radio、select、checkbox、layer 这四种表单项,需要加载额外的选单数据
* 选单数据有两种获取方式:
* 1、来自数据字典:
* 数据字典在 this.GET_GLOBAL('dataDictionary')
* 表单使用的字段在 schemeItem.itemCode
* 选单数据中的 text 字段作为显示, value 字段作为值
*
* 2、来自数据源:
* 将 schemeItem.dataSourceId 按符号「,」逗号分割为数组,分割为: [code, displayField, valueField]
* 数据源需要请求 API 来获取,请求需要带上数据源的编号 code
* displayField、valueField 分别为展示字段和值绑定字段
*
* 选单数据有两种格式:
* 1、对于 radio、select、checkbox 来说:
* 只需要一个数组,数组形如: [{ text: '选项文字', value: '选项值' }, ...]
* 将获取的数据绑定到组件的 range 属性上即可
* 全局数据中默认是对象形式,使用 Object.values() 转化即可
*
* 2、对于 layer 来说:
* 返回一个对象,形如 { source, layerData, selfField }
* source: 为弹层中列出的数据,是一个数组
* layerData: 需要在弹层窗口中展示的字段及标题文字,形如: [{ name:'要展示的字段名', label:'标题文字' }]
* selfField: 该表单值绑定哪个字段,默认为绑定到自身的字段
*/
async getSourceData(schemeItem) {
if (['radio', 'select', 'checkbox'].includes(schemeItem.type)) {
// radio select checkbox 三种情况
if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) {
// dataSource 为 0,使用 clientData
return Object
.values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode])
.map(t => ({
value: t.value,
text: t.text
}))

} else {
// dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段
const [code, displayField = schemeItem.showField, valueField = schemeItem.saveField] =
schemeItem.dataSourceId
.split(',')
const sourceData = await this.FETCH_DATASOURCE(code)
if (!sourceData) {
return []
}

return sourceData.data.map(t => ({
text: t[displayField],
value: t[valueField]
}))
}

} else if (['layer'].includes(schemeItem.type)) {
// layer 需要更多属性
if (!schemeItem.dataSource || Number(schemeItem.dataSource) === 0) {
// dataSource 为 0,使用 clientData
// clientData 对象转数组后,隐含 key:item.text 和 value:item.value 的关系
const [keyItem, valueItem] = schemeItem.layerData
const source = Object
.values(this.GET_GLOBAL('dataDictionary')[schemeItem.itemCode])
.map(t => ({
value: t.value,
text: t.text
}))

return {
source,
layerData: [{
name: 'text',
label: keyItem.label || '',
value: keyItem.value || ''
},
{
name: 'value',
label: valueItem.label || '',
value: valueItem.value || ''
}
]
}
} else {
// dataSource 不为 0,使用数据源,需要请求接口,并且提取出显示字段和实际字段
const [code] = schemeItem.dataSourceId.split(',')
const sourceData = await this.FETCH_DATASOURCE(code)
if (!sourceData) {
return []
}

const source = sourceData.data

return {
source,
layerData: schemeItem.layerData.filter(t => (!t.hide) && (t.value || t.label))
}
}
}

return []
},

/**
* 获取一个 scheme 表单项的默认值 (用户新建表单时使用,或是编辑草稿)
* 参数: 单个 schemeItem , { processId }
*
* 每种类别的表单项分别获取的默认值:
*
* currentInfo: 根据类别取当前用户/部门/公司/时间日期
* datetime: 根据 dfValue 字段表示昨天/今天/明天,格式化为字符串
* radio、select: 有 dfValue 则使用,否则取第一条
* checkbox: 有 dfValue 则使用,否则为空数组
* encode: 根据 rulecode 请求表单编码
* upload: 空数组
* guid: 赋值第二个参数中的 processId,但是如果在子表格中,赋空字符串
* girdtable: 递归所有表格项 scheme 依次为它们生成默认值
* datetimerange: 字符串 0
*/
async getDefaultData(item, prop) {
const {
processId
} = prop
switch (item.type) {
case 'currentInfo':
switch (item.dataType) {
case 'user':
return this.GET_GLOBAL('loginUser').userId
case 'department':
return this.GET_GLOBAL('loginUser').departmentId
case 'company':
return this.GET_GLOBAL('loginUser').companyId
case 'time':
return moment().format('YYYY-MM-DD HH:mm:ss')
default:
return ''
}

case 'datetime':
const datetimeFormat = item.table ?
(Number(item.dateformat) === 0 ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss') :
(item.datetime === 'datetime' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
const today = moment()
const dfDatetime = [
today.subtract(1, 'day'),
today,
today.add(1, 'day')
][Number(item.dfvalue)] || today

return dfDatetime.format(datetimeFormat) || ''

case 'radio':
case 'select':
const radioItem = item.__sourceData__.find(t => t.value === item.dfvalue) || item
.__sourceData__[0]
return item.type === 'radio' ? radioItem.value : ''

case 'checkbox':
if (!item.dfvalue) {
return []
}
return item.dfvalue.split(',').filter(t => item.__sourceData__.find(s => s.value === t))

case 'encode':
const result = await this.FETCH_ENCODE(item.rulecode)
return result

case 'upload':
return []

case 'guid':
return item.table ? processId : ''

case 'girdtable':
const tableItemObj = {}
for (const fieldItem of item.fieldsData) {
tableItemObj[fieldItem.field] = await this.getDefaultData(fieldItem, prop)
}
return this.COPY(tableItemObj)

case 'datetimerange':
return '0'

default:
return item.dfvalue || ''
}
},

/**
* 将单条 formData 值转化为 formValue 值 (拉取表单数据时使用)
* 参数: 单个 schemeItem , 数据值
*
* 具体执行逻辑:
* radio、select: 剔除无效值
* checkbox: 分割成数组并剔除无效值
* upload: 分割成数组,拉取其中所有文件的信息
* datetime: 按照时间日期格式进行格式化字符串
* 其他类型: 保留原值
*/
async convertToFormValue(item, val) {
switch (item.type) {
case 'upload':
if (!val) {
return []
}
const uidList = val;
const fileList = []
const wxlist = await this.FETCH_FILEList(uidList);
for (const wxfile of wxlist) {
const fileInfo = await this.FETCH_FILEINFO(wxfile.F_Id)
if (!fileInfo) {
continue
}

const fileType = fileInfo.F_FileType
const fileSize = fileInfo.F_FileSize

const path = this.API + '/learun/adms/annexes/wxdown?' + this.URL_QUERY(wxfile.F_Id, true)
fileList.push({
path,
type: fileType,
uid:wxfile.F_Id,
folderId:wxfile.F_FolderId,
size: fileSize
})
}
return fileList

case 'select':
case 'radio':
if (!val || !item.__sourceData__.map(t => t.value).includes(val)) {
return ''
}
return val

case 'checkbox':
const validValue = item.__sourceData__.map(t => t.value)
const checkboxVal = val.split(',') || []
return checkboxVal.filter(t => validValue.includes(t))

case 'datetime':
if (!val) {
return ''
}
return moment(val).format(
Number(item.dateformat) === 0 || item.datetime === 'date' ?
'YYYY-MM-DD' :
'YYYY-MM-DD HH:mm:ss'
)

default:
return val || ''
}
},

/**
* 将一个 formValue 值转化为 post 提交值(提交表单数据时使用)
* 参数: 单个 schemeItem , 表单项值 , 所有 formValue , scheme
*
* 具体执行逻辑:
* checkbox: 将数组使用符号「,」逗号拼接成字符串
* datetimerange: 获取开始日期、结束日期,计算差值天数并保留整数
* datetime: 格式化为完整时间日期字符串
* upload: 依次上传文件,将返回的文件 ID 使用符号「,」逗号拼接成字符串
* 其他类型: 保留原值
*/
async convertToPostData(item, val, formValue, scheme, guid) {
switch (item.type) {
case 'checkbox':
return val ? val.join(',') : ''

case 'datetimerange':
const startTime = get(formValue, scheme.find(t => t.id === item.startTime).__valuePath__, null)
const endTime = get(formValue, scheme.find(t => t.id === item.endTime).__valuePath__, null)
if (!startTime || !endTime || moment(endTime).isBefore(startTime)) {
return ''
} else {
return moment.duration(moment(endTime).diff(moment(startTime))).asDays().toFixed(0)
}

case 'datetime':
return val ? moment(val).format('YYYY-MM-DD HH:mm:ss') : ''

case 'upload':
var uploadUid = '';

for (const item of val) {
if (item.uid) {
uploadUid = item.uid
continue
}

const fileId = await this.HTTP_UPLOAD(item.path || item, undefined, guid || '')
if (fileId) {
uploadUid = fileId;
}
}

return uploadUid;

default:
return val || ''
}
}
}
}

+ 0
- 1
Learun.Framework.Ultimate V7/LearunApp-2.2.0/common/custompage.js Voir le fichier

@@ -257,7 +257,6 @@ export default {
const fileSize = fileInfo.F_FileSize

const path = this.API + '/learun/adms/annexes/wxdown?' + this.URL_QUERY(uid, true)

fileList.push({ path, type: fileType, uid, size: fileSize })
}
return fileList


+ 13
- 4
Learun.Framework.Ultimate V7/LearunApp-2.2.0/common/mixins.js Voir le fichier

@@ -229,6 +229,14 @@ export default {

return await this.HTTP_GET('learun/adms/annexes/wxfileinfo', fileId)
},
//获取文件夹下文件列表
async FETCH_FILEList(folderId) {
if (!folderId) {
return null
}
return await this.HTTP_GET('learun/adms/annexes/wxlist', folderId)
},

// 封装的 GET 请求,集成了验证信息
// 返回请求结果或 null
@@ -258,8 +266,8 @@ export default {
// url 为请求地址
// filePath 为临时文件的路径
// formData 为请求附带的提交数据
async HTTP_UPLOAD(filePath, formData) {
const [err, res] = await this.UPLOAD('/learun/adms/annexes/wxupload', filePath, formData)
async HTTP_UPLOAD(filePath, formData,guid) {
const [err, res] = await this.UPLOAD('/learun/adms/annexes/wxupload', filePath, formData,guid)

return this.handleResult(err, res)
},
@@ -308,11 +316,12 @@ export default {
// 返回结果是一个数组: [error, result]
// error 表示错误,一般是网络错误,请求很可能根本没有发出
// result 包含 { statusCode, data } 分别表示状态码、接口返回的数据
async UPLOAD(url, filePath, formData) {
async UPLOAD(url, filePath, formData,guid) {
const uploadUrl = this.handleUrl(url)
const query = {
loginMark: this.getLoginMark(),
token: this.GET_GLOBAL('token')
token: this.GET_GLOBAL('token'),
folderId:guid
}

if (formData && typeof formData === 'object') {


+ 2
- 2
Learun.Framework.Ultimate V7/LearunApp-2.2.0/config.js Voir le fichier

@@ -21,8 +21,8 @@ export default {
// "http://192.168.2.98:8088/"
// ],
"apiHost": [
// "http://localhost:31173/"
"http://192.168.10.68:8002/"
"http://localhost:31173/"
//"http://192.168.10.68:8002/"
],
"webHost":"http://localhost:20472/",
// 开发环境下自动填充登录账号密码,与接口地址一一对应,只在开发环境下显示


+ 1
- 1
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/msg.vue Voir le fichier

@@ -132,7 +132,7 @@ export default {
return null
}

return this.API + `/user/img?data=${item.F_OtherUserId}`
return this.API + `/learun/adms/user/img?data=${item.F_OtherUserId}`
}
},



+ 1
- 1
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/msg/chat.vue Voir le fichier

@@ -186,7 +186,7 @@ export default {

// 获取用户头像图片 url
avatar(id) {
return id === this.chatUserId && this.isSystem ? null : this.API + `/user/img?data=${id}`
return id === this.chatUserId && this.isSystem ? null : this.API + `/learun/adms/user/img?data=${id}`
}
},



+ 1
- 1
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/my.vue Voir le fichier

@@ -156,7 +156,7 @@ export default {
return ''
}

return this.API + `/user/img?data=${this.currentUser.userId}`
return this.API + `/learun/adms/user/img?data=${this.currentUser.userId}`
}
},



+ 1
- 1
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/my/info.vue Voir le fichier

@@ -34,7 +34,7 @@ export default {
// 头像图片 url
avatarSrc() {
return this.API + `/user/img?data=${this.currentUser.userId}`
return this.API + `/learun/adms/user/img?data=${this.currentUser.userId}`
}
}
}


+ 1
- 1
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/my/qrcode.vue Voir le fichier

@@ -30,7 +30,7 @@ export default {

// 头像图片 url
avatar() {
return this.API + `/user/img?data=${this.currentUser.userId}`
return this.API + `/learun/adms/user/img?data=${this.currentUser.userId}`
},

// 用户公司部门 tag


+ 0
- 5
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/myflow/single.vue Voir le fichier

@@ -95,7 +95,6 @@ export default {
// t.formId 使用表单,根据这个 formId 来获取 scheme 等信息
// t.appurl 使用移动页面,直接跳转到本地的页面;表单结构等均写死在页面里
const { wfForms } = this.currentNode
console.log(wfForms);

// 处理没有有效表单的情况,停止加载
if (!wfForms || wfForms.every(t => !t.formId && !t.appurl)) {
@@ -144,7 +143,6 @@ export default {
code: this.code,
useDefault: true
})
console.log("formValue",formValue,"scheme",scheme)
this.scheme = scheme
this.formValue = formValue
this.rel = rel
@@ -152,8 +150,6 @@ export default {
// 不是子流程,可以直接渲染
const schemeData = await this.fetchSchemeData(this.currentNode)
const formData = await this.fetchFormData(this.currentNode, this.processId)
console.log(schemeData)
console.log(formData)
const { formValue, scheme, rel } = await this.getCustomForm({
formData,
schemeData,
@@ -161,7 +157,6 @@ export default {
processId: this.processId,
code: null
})
console.log("formValue",formValue,"scheme",scheme)
this.scheme = scheme
this.formValue = formValue
this.rel = rel


+ 5
- 2
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/releasetask/single.vue Voir le fichier

@@ -110,7 +110,9 @@ export default {

this.needTitle = this.type !== 'again' && Number(currentNode.isTitle) === 1
const formData = await this.fetchFormData(currentNode, processId)
const schemeData = await this.fetchSchemeData(currentNode)
const { formValue, scheme, rel } = await this.getCustomForm({
schemeData,
processId,
@@ -119,14 +121,16 @@ export default {
code: this.type === 'again' ? null : code,
useDefault: true
})
this.rel = rel
this.scheme = scheme
this.formValue = formValue
this.code = code
this.processId = processId
console.log(this.formValue,'=====',this.scheme ,)
this.ready = true
this.HIDE_LOADING()
},

// 提交草稿按钮
@@ -194,7 +198,6 @@ export default {
verifyValue() {
const errList = this.$refs.form.verifyValue()
console.log(errList,'errList')
if (this.needTitle && !this.title) {
errList.push(`流程的标题不能为空`)
}


+ 351
- 297
Learun.Framework.Ultimate V7/LearunApp-2.2.0/pages/nworkflow/workflow.js Voir le fichier

@@ -32,301 +32,355 @@ import customForm from '@/common/customform.js'
* (以上只是简单介绍;实际使用中,如果打开子流程,需要拉取父/子两个流程信息)
*/
export default {
mixins: [customForm],

methods: {
/**
* 从流程信息中生成 scheme、formValue
* 参数: { schemeData (必填), processId, currentNode, formData (新建时为 null), code, useDefault }
* 返回: { scheme, formValue, rel }
*
* 参数:
* schemeData: 使用 fetchSchemeData 方法拉取到的原始 scheme 数据,未经过格式化处理
* processId: 表单 GUID;如果是新建表单,可以用 this.GUID('-') 生成一个
* currentNode: 使用 getCurrentNode 方法拉取到的当前节点信息,用于权限控制
* formData: 填入表单的表单值,新建表单时此项为 null 即可
* code: 表单编号 code,会被赋值到返回的 formValue.code;重新发起流程的场合赋 null
* useDefault: 如果 formData 中某一项为空,是否对这一项填入默认值;通常在编辑草稿时启用
*
* 该方法返回的 scheme 项可能带有以下属性:
* __valuePath__: 表单值在 formValue 中的路径,使用 lodash 的 get、set 方法即可读写
* __sourceData__: 表单值的选单数据
* __defaultItem__: 类型为 girdtable 的表单项带有此属性,表示添加一行表格时候表格项的默认值
* __schemeIndex__: (暂时用不到)表单项位于 schemeData 根级内的第几个子项中
* __dataIndex__: (暂时用不到)表单项位于 F_Scheme.data 中的第几个子项中
*/
async getCustomForm(prop) {
const { schemeData, formData, currentNode, code, processId, useDefault } = prop
console.log(prop,'prop')
// 处理字段之间的级联、绑定关系
// 需要绑定 change 事件的:
// datetime: 修改后重新计算 datetimerange
// organize: 修改后重设级联到该组件的其他组件的值,user 一级无需处理
// 需要绑定某值的:
// organize: 级联到某个组件,company 一级无需处理
const schemeRef = {}
const refList = []

// 最终返回值:scheme、rel、formValue
const scheme = []
const rel = {}
const formValue = { processId, formreq: [] }
if (code) {
formValue.code = code
}

// 遍历 schemeData 中所有的 scheme
const schemeList = Array.isArray(schemeData) ? schemeData : Object.values(schemeData)
for (let schemeIndex = 0; schemeIndex < schemeList.length; ++schemeIndex) {
const schemeItem = schemeList[schemeIndex]
schemeItem.F_Scheme = JSON.parse(schemeItem.F_Scheme)
// 已有表单值的时候,舍弃掉不存在表单值中的 scheme
if (formData && !formData[schemeItem.F_SchemeInfoId]) {
continue
}
// 设置 formreq 的内容,非新建模式下需要设置 keyValue
const { formId, field } = get(currentNode, `wfForms.${schemeIndex}`, {})
const formreqObj = { schemeInfoId: formId, processIdName: field, formData: {} }
if (formData) {
if (Object.values(get(formData, `${schemeItem.F_SchemeInfoId}`, {})).some(t => t && t.length > 0)) {
formreqObj.keyValue = processId
}
}
formValue.formreq[schemeIndex] = formreqObj

for (let dataIndex = 0; dataIndex < schemeItem.F_Scheme.data.length; ++dataIndex) {
const { componts } = schemeItem.F_Scheme.data[dataIndex]
for (const t of componts) {
// 之后的 t 即表示每个 scheme 项
t.__valuePath__ = `formreq.${schemeIndex}.formData.${t.id}`
// 以下两个属性暂时用不到
t.__schemeIndex__ = schemeIndex
t.__dataIndex__ = dataIndex

if (t.type === 'girdtable' && t.table) {
// 数据项是表格的情况
// 先设置源数据,不然无法获取默认值
for (const fieldItem of t.fieldsData) {
fieldItem.__sourceData__ = await this.getSourceData(fieldItem)
}
t.__defaultItem__ = await this.getDefaultData(t, prop)
if (formData) {
// 有表单值的情况,从表单值中获取数据
const val = []
for (const valueItem of get(formData, `${schemeItem.F_SchemeInfoId}.${t.table}`, [])) {
const tableItemValue = {}
for (const fieldItem of t.fieldsData.filter(t => t.field)) {
const formDataValue = get(valueItem, fieldItem.field.toLowerCase())
tableItemValue[fieldItem.field] = await this.convertToFormValue(fieldItem, formDataValue)
}

val.push(tableItemValue)
}

// useDefault 表示在从 formData 取不到值的时候使用默认值
if ((!val || val.length <= 0) && useDefault) {
set(formValue, t.__valuePath__, [this.COPY(t.__defaultItem__)])
} else {
set(formValue, t.__valuePath__, val)
}

} else {
// 无表单值的情况,默认值
set(formValue, t.__valuePath__, [this.COPY(t.__defaultItem__)])
}

} else if (t.field) {
// 数据项不是表格的情况
// 先设置源数据,不然无法获取默认值
t.__sourceData__ = await this.getSourceData(t)
if (formData) {
// 有表单值的情况,从表单值中获取数据
const path = `${schemeItem.F_SchemeInfoId}.${t.table}.${dataIndex}.${t.field.toLowerCase()}`
const formDataValue = get(formData, path)

// useDefault 表示在从 formData 取不到值的时候使用默认值
if (!formDataValue && useDefault) {
set(formValue, t.__valuePath__, await this.getDefaultData(t, prop))
} else {
set(formValue, t.__valuePath__, await this.convertToFormValue(t, formDataValue))
}

} else {
// 无表单值的情况,默认值
set(formValue, t.__valuePath__, await this.getDefaultData(t, prop))
}
}

// 权限控制
const authObj = get(currentNode, `wfForms.${schemeIndex}.authorize.${t.id}`, {})
t.edit = authObj.isEdit
if (Number(t.isHide) !== 1 && authObj.isLook !== 0) {
// 加入 scheme
scheme.push(t)

// organize、datetime 可能作为其他 organize 或 datetimerange 的依赖项,引用它们
if (['organize', 'datetime'].includes(t.type)) {
schemeRef[t.id] = t
}

// datetimerange、带有 relation 级联字段的 organize,依赖其他项
if ((t.type === 'datetimerange' && t.startTime && t.endTime) || (t.type === 'organize' && t.relation)) {
refList.push(t)
}
}
}
}
}

// 依次处理表单关联
refList.forEach(t => {
if (t.type === 'organize') {
// 处理组件结构级联
// 给当前组件赋上级级联的值路径 __relationPath__
const parent = schemeRef[t.relation]
t.__relationPath__ = parent.__valuePath__
// 给上级级联的组件注册自动重置当前组件的 change 事件
const relItem = { type: 'organize', id: t.id, path: t.__valuePath__ }
rel[parent.id] = rel[parent.id] ? rel[parent.id].concat(relItem) : [relItem]

} else if (t.type === 'datetimerange') {
// 处理日期区间
const start = schemeRef[t.startTime]
const end = schemeRef[t.endTime]

const relItem = {
type: 'datetimerange',
path: t.__valuePath__,
id: t.id,
startPath: start.__valuePath__,
endPath: end.__valuePath__,
}

rel[start.id] = rel[start.id] ? rel[start.id].concat(relItem) : [relItem]
rel[end.id] = rel[end.id] ? rel[end.id].concat(relItem) : [relItem]

}
})

return { scheme, formValue, rel }
},

/**
* 获取最终需要 POST 的数据
* 参数:formValue, scheme
* 返回:用于提交的数据
*
* 遍历 formValue,将其中的表单值依次使用 convertToPostData 这个方法转化为提交值
*/
async getPostData(originFormValue, scheme) {
const formValue = this.COPY(originFormValue)

// 依次按照 scheme 项目遍历
for (const item of scheme) {
if (item.field) {
// 不是表格的情况
const path = item.__valuePath__
const val = get(formValue, path)
console.log(val,'val=======')
const result = await this.convertToPostData(item, val, originFormValue, scheme)
set(formValue, path, result)

} else if (item.table && item.fieldsData) {
// 是表格的情况
const tableValue = get(formValue, item.__valuePath__, [])
for (let valueIndex = 0; valueIndex < tableValue.length; ++valueIndex) {
for (const schemeItem of item.fieldsData) {
const path = `${item.__valuePath__}.${valueIndex}.${schemeItem.field}`
const val = get(formValue, path)
const result = await this.convertToPostData(schemeItem, val, originFormValue, scheme)
set(formValue, path, result)
}
}
}
}

formValue.formreq.forEach(t => { t.formData = JSON.stringify(t.formData) })
formValue.formreq = JSON.stringify(formValue.formreq)

return formValue
},

/**
* 获取流程信息
* 参数: { code, processId, taskId }
*
*/
async fetchProcessInfo({ code, processId, taskId }) {
const url = processId ? 'learun/adms/newwf/processinfo' : 'learun/adms/newwf/scheme'
const reqObj = { processId }
if (taskId) {
reqObj.taskId = taskId
}
const data = processId ? reqObj : code
const result = await this.HTTP_GET(url, data)

if (!result) { return {} }

if (result.info) {
result.info.Scheme = JSON.parse(result.info.Scheme)
} else if (result.F_Content) {
result.F_Content = JSON.parse(result.F_Content)
}

return result
},

/**
* 从 processInfo 流程信息中,提取出 currentNode
* 参数: processInfo
*
*/
getCurrentNode(processInfo) {
if (processInfo.info) {
return processInfo.info.Scheme.nodes.find(t => t.id === processInfo.info.CurrentNodeId)
} else if (processInfo.F_Content) {
return processInfo.F_Content.nodes.find(t => t.type === 'startround')
}

return {}
},

/**
* 拉取表单的 schemeData
* 参数: currentNode
*
* 从当前节点 currentNode 中提取出表单 id,然后自 API 地址 /form/scheme 中拉取表单数据并返回
*/
async fetchSchemeData(currentNode, currentTask, type) {
const { wfForms } = currentNode

const data = wfForms.filter(t => t.formId).map(t => ({ id: t.formId, ver: '' }))
const schemeData = await this.HTTP_GET('learun/adms/form/scheme', data)

return schemeData || {}
},

/**
* 拉取表单的 formData
* 参数: currentNode, keyValue
*
* 提取当前节点信息、表单主键信息,从 API 地址 /form/data 中拉取表单数据
*/
async fetchFormData({ wfForms }, keyValue) {
const reqData = wfForms
.filter(t => t.formId)
.map(t => ({
schemeInfoId: t.formId,
processIdName: t.field,
keyValue
}))

const formData = await this.HTTP_GET('learun/adms/form/data', reqData)

return formData || {}
}
}
mixins: [customForm],

methods: {
/**
* 从流程信息中生成 scheme、formValue
* 参数: { schemeData (必填), processId, currentNode, formData (新建时为 null), code, useDefault }
* 返回: { scheme, formValue, rel }
*
* 参数:
* schemeData: 使用 fetchSchemeData 方法拉取到的原始 scheme 数据,未经过格式化处理
* processId: 表单 GUID;如果是新建表单,可以用 this.GUID('-') 生成一个
* currentNode: 使用 getCurrentNode 方法拉取到的当前节点信息,用于权限控制
* formData: 填入表单的表单值,新建表单时此项为 null 即可
* code: 表单编号 code,会被赋值到返回的 formValue.code;重新发起流程的场合赋 null
* useDefault: 如果 formData 中某一项为空,是否对这一项填入默认值;通常在编辑草稿时启用
*
* 该方法返回的 scheme 项可能带有以下属性:
* __valuePath__: 表单值在 formValue 中的路径,使用 lodash 的 get、set 方法即可读写
* __sourceData__: 表单值的选单数据
* __defaultItem__: 类型为 girdtable 的表单项带有此属性,表示添加一行表格时候表格项的默认值
* __schemeIndex__: (暂时用不到)表单项位于 schemeData 根级内的第几个子项中
* __dataIndex__: (暂时用不到)表单项位于 F_Scheme.data 中的第几个子项中
*/
async getCustomForm(prop) {
const {
schemeData,
formData,
currentNode,
code,
processId,
useDefault
} = prop
// 处理字段之间的级联、绑定关系
// 需要绑定 change 事件的:
// datetime: 修改后重新计算 datetimerange
// organize: 修改后重设级联到该组件的其他组件的值,user 一级无需处理
// 需要绑定某值的:
// organize: 级联到某个组件,company 一级无需处理
const schemeRef = {}
const refList = []

// 最终返回值:scheme、rel、formValue
const scheme = []
const rel = {}
const formValue = {
processId,
formreq: []
}
if (code) {
formValue.code = code
}

// 遍历 schemeData 中所有的 scheme
const schemeList = Array.isArray(schemeData) ? schemeData : Object.values(schemeData)
for (let schemeIndex = 0; schemeIndex < schemeList.length; ++schemeIndex) {

const schemeItem = schemeList[schemeIndex]
schemeItem.F_Scheme = JSON.parse(schemeItem.F_Scheme)
// 已有表单值的时候,舍弃掉不存在表单值中的 scheme
if (formData && !formData[schemeItem.F_SchemeInfoId]) {
continue
}

// 设置 formreq 的内容,非新建模式下需要设置 keyValue
const {
formId,
field
} = get(currentNode, `wfForms.${schemeIndex}`, {})
const formreqObj = {
schemeInfoId: formId,
processIdName: field,
formData: {}
}
if (formData) {
if (Object.values(get(formData, `${schemeItem.F_SchemeInfoId}`, {})).some(t => t && t.length >
0)) {
formreqObj.keyValue = processId
}
}
formValue.formreq[schemeIndex] = formreqObj

for (let dataIndex = 0; dataIndex < schemeItem.F_Scheme.data.length; ++dataIndex) {
const {
componts
} = schemeItem.F_Scheme.data[dataIndex]
for (const t of componts) {
// 之后的 t 即表示每个 scheme 项
t.__valuePath__ = `formreq.${schemeIndex}.formData.${t.id}`
// 以下两个属性暂时用不到
t.__schemeIndex__ = schemeIndex
t.__dataIndex__ = dataIndex

if (t.type === 'girdtable' && t.table) {
// 数据项是表格的情况
// 先设置源数据,不然无法获取默认值
for (const fieldItem of t.fieldsData) {
fieldItem.__sourceData__ = await this.getSourceData(fieldItem)
}
t.__defaultItem__ = await this.getDefaultData(t, prop)
if (formData) {
// 有表单值的情况,从表单值中获取数据
const val = []
for (const valueItem of get(formData, `${schemeItem.F_SchemeInfoId}.${t.table}`,
[])) {
const tableItemValue = {}
for (const fieldItem of t.fieldsData.filter(t => t.field)) {
const formDataValue = get(valueItem, fieldItem.field.toLowerCase())
tableItemValue[fieldItem.field] = await this.convertToFormValue(fieldItem,
formDataValue)
}

val.push(tableItemValue)
}

// useDefault 表示在从 formData 取不到值的时候使用默认值
if ((!val || val.length <= 0) && useDefault) {
set(formValue, t.__valuePath__, [this.COPY(t.__defaultItem__)])
} else {
set(formValue, t.__valuePath__, val)
}

} else {
// 无表单值的情况,默认值
set(formValue, t.__valuePath__, [this.COPY(t.__defaultItem__)])
}

} else if (t.field) {
// 数据项不是表格的情况
// 先设置源数据,不然无法获取默认值
t.__sourceData__ = await this.getSourceData(t)
if (formData) {
// 有表单值的情况,从表单值中获取数据
const path =
`${schemeItem.F_SchemeInfoId}.${t.table}.${dataIndex}.${t.field.toLowerCase()}`
const formDataValue = get(formData, path)

// useDefault 表示在从 formData 取不到值的时候使用默认值
if (!formDataValue && useDefault) {
set(formValue, t.__valuePath__, await this.getDefaultData(t, prop))
} else {
set(formValue, t.__valuePath__, await this.convertToFormValue(t, formDataValue))
}

} else {
// 无表单值的情况,默认值
set(formValue, t.__valuePath__, await this.getDefaultData(t, prop))
}
}

// 权限控制
const authObj = get(currentNode, `wfForms.${schemeIndex}.authorize.${t.id}`, {})
t.edit = authObj.isEdit
if (Number(t.isHide) !== 1 && authObj.isLook !== 0) {
// 加入 scheme
scheme.push(t)

// organize、datetime 可能作为其他 organize 或 datetimerange 的依赖项,引用它们
if (['organize', 'datetime'].includes(t.type)) {
schemeRef[t.id] = t
}

// datetimerange、带有 relation 级联字段的 organize,依赖其他项
if ((t.type === 'datetimerange' && t.startTime && t.endTime) || (t.type ===
'organize' && t.relation)) {
refList.push(t)
}
}
}
}
}

// 依次处理表单关联
refList.forEach(t => {
if (t.type === 'organize') {
// 处理组件结构级联
// 给当前组件赋上级级联的值路径 __relationPath__
const parent = schemeRef[t.relation]
t.__relationPath__ = parent.__valuePath__
// 给上级级联的组件注册自动重置当前组件的 change 事件
const relItem = {
type: 'organize',
id: t.id,
path: t.__valuePath__
}
rel[parent.id] = rel[parent.id] ? rel[parent.id].concat(relItem) : [relItem]

} else if (t.type === 'datetimerange') {
// 处理日期区间
const start = schemeRef[t.startTime]
const end = schemeRef[t.endTime]

const relItem = {
type: 'datetimerange',
path: t.__valuePath__,
id: t.id,
startPath: start.__valuePath__,
endPath: end.__valuePath__,
}

rel[start.id] = rel[start.id] ? rel[start.id].concat(relItem) : [relItem]
rel[end.id] = rel[end.id] ? rel[end.id].concat(relItem) : [relItem]

}
})

return {
scheme,
formValue,
rel
}
},
newguid(){
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
/**
* 获取最终需要 POST 的数据
* 参数:formValue, scheme
* 返回:用于提交的数据
*
* 遍历 formValue,将其中的表单值依次使用 convertToPostData 这个方法转化为提交值
*/
async getPostData(originFormValue, scheme) {
const formValue = this.COPY(originFormValue)
var guid =this.newguid();
// 依次按照 scheme 项目遍历
for (const item of scheme) {
if (item.field) {
// 不是表格的情况
const path = item.__valuePath__
const val = get(formValue, path)
const result = await this.convertToPostData(item, val, originFormValue, scheme, guid)
set(formValue, path, result)

} else if (item.table && item.fieldsData) {
// 是表格的情况
const tableValue = get(formValue, item.__valuePath__, [])
for (let valueIndex = 0; valueIndex < tableValue.length; ++valueIndex) {
for (const schemeItem of item.fieldsData) {
const path = `${item.__valuePath__}.${valueIndex}.${schemeItem.field}`
const val = get(formValue, path)

const result = await this.convertToPostData(schemeItem, val, originFormValue, scheme,
guid)
set(formValue, path, result)
}
}
}
}

formValue.formreq.forEach(t => {
t.formData = JSON.stringify(t.formData)
})
formValue.formreq = JSON.stringify(formValue.formreq)

return formValue
},

/**
* 获取流程信息
* 参数: { code, processId, taskId }
*
*/
async fetchProcessInfo({
code,
processId,
taskId
}) {
const url = processId ? 'learun/adms/newwf/processinfo' : 'learun/adms/newwf/scheme'
const reqObj = {
processId
}
if (taskId) {
reqObj.taskId = taskId
}
const data = processId ? reqObj : code
const result = await this.HTTP_GET(url, data)

if (!result) {
return {}
}

if (result.info) {
result.info.Scheme = JSON.parse(result.info.Scheme)
} else if (result.F_Content) {
result.F_Content = JSON.parse(result.F_Content)
}

return result
},

/**
* 从 processInfo 流程信息中,提取出 currentNode
* 参数: processInfo
*
*/
getCurrentNode(processInfo) {
if (processInfo.info) {
return processInfo.info.Scheme.nodes.find(t => t.id === processInfo.info.CurrentNodeId)
} else if (processInfo.F_Content) {
return processInfo.F_Content.nodes.find(t => t.type === 'startround')
}

return {}
},

/**
* 拉取表单的 schemeData
* 参数: currentNode
*
* 从当前节点 currentNode 中提取出表单 id,然后自 API 地址 /form/scheme 中拉取表单数据并返回
*/
async fetchSchemeData(currentNode, currentTask, type) {
const {
wfForms
} = currentNode

const data = wfForms.filter(t => t.formId).map(t => ({
id: t.formId,
ver: ''
}))
const schemeData = await this.HTTP_GET('learun/adms/form/scheme', data)

return schemeData || {}
},

/**
* 拉取表单的 formData
* 参数: currentNode, keyValue
*
* 提取当前节点信息、表单主键信息,从 API 地址 /form/data 中拉取表单数据
*/
async fetchFormData({
wfForms
}, keyValue) {
const reqData = wfForms
.filter(t => t.formId)
.map(t => ({
schemeInfoId: t.formId,
processIdName: t.field,
keyValue
}))

const formData = await this.HTTP_GET('learun/adms/form/data', reqData)

return formData || {}
}
}
}

Chargement…
Annuler
Enregistrer