mirror of
https://github.com/getrebuild/rebuild.git
synced 2025-10-26 08:47:29 +08:00
* Update @rbv * feat: trigger when update-fields approve-nodes (#728) * ** NEED TEST ** * Update metadata-conf.xml * 3.7-dev * bump: echarts v5 * COLOR_PALETTES * be: DlgSpecFields into common * feat: spec approval-node trigger * feat: hasUpdateFields for all * tmp: RobotSopConfig * Update @rbv * enh: TriggerByTimerJob 未完成也可重进 (#731) * enh: TriggerByTimerJob 未完成也可重进 * enh: fileName use#698 * feat: UseDbFullText * !!!@EnableAsync --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * feat: chart CNMAP (#732) * style: chart in datalist * feat: CNMAP * feat: Details auto imports 110 (#733) * js: $.trim, $.isArray, click-on * feat: details import auto * enh: $type, select2 * Add lib react18 * bump lib * Update lint.yml --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Update @rbv * Enh auto approval (#735) * rbv: AutoApproval * console: RBAPI ASSISTANT * Update @rbv * print Approval Node * filter: op=HHH * feat: AutoApproval * be: use tags * be: LastLogsViewer.renderLog * Feat list3 card 100 (#737) * style * datalist conf * feat: mode3 * mode23 style * enh: datalist2 * fjs: openModal, getType * Update @rbv * bump: react18, jq (#738) * js: $.trim, $.isArray, click-on * feat: details import auto * enh: $type, select2 * Add lib react18 * enh: js * bump lib * react18 * cnmap style * actions * loadmore style --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * feat: approval step users (#739) * feat: approvalLastTime * feat: approvalStepUsers * img indicator * Update @rbv * be: filter * submail attach --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Notify use sms email (#741) * feat: EmailDistributor, SmsDistributor * feat: ApprovalStepNodeName * isOceanBase --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Update @rbv * Update @rbv * feat: Auto create task 119 (#742) feat: CreateTask feat:SMS/EmailDistributor * be: save cb * entity searchbox * feat: REP * Chart axis 120 (#743) * style: CNMAP * feat: Stack Bar * feat: showHorizontal * be --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Approval expires 114 (#745) * feat: expiresAuto * be: approval copy * be:entity view by code * feat: tasks list (#746) * style: icon of chart * feat: project list tasks * be: setEditableFields keep sort Gitee#I9EGJB * be: executeLazy * Nd trans (#747) * enh: getDisksUsed * be: link entity * feat: ND trans * style * be: filter * icon: zmdi-filter-list * style: list badge 12px * detailImports * style project * be: $multipleUploader * feat: sop (#748) * be * be: trans 1>N * enh: sql ver * styles * ps style * feat: sop * enh: useExecManual for all --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Update forms.html * Report use cond (#749) * style * be: sop * feat: report useFilter * field image _captureType * TSID error --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Feat datasync 94 (#750) * be: ref-search pageSize=20 * feat: date W Gitee#I9I67Z * style * feat: bar3 * be: charts style * feat: DataSyncer spec * Enh extforms (#752) * dock style * enh: trigger edit code * fix: guide * trubo * fix: Add no-rollback-for=RepeatedRecordsException * 通过》已完成 * be: charts * enh: .detail-form-table.fullscreen * fix: Gitee#I9J3UR https://github.com/alibaba/easyexcel/issues/3432 * ExcelClipboardData * Update README.md --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Update @rbv * Feat excel clipboard data (#753) * style * feat: csvdata-rebuild * enh: DataListCategory (Use tree) * be: Nval duplicate * Apidock (#754) * TsetEntity * theme color * be: trigger on update * rm: LazyWaitDetailsFinished * apiman * fix: ApprovalStepNodeName * Enh charts (#755) * enh: axis filter * enh: FunnelChart * feat: SendNotification email attach * AutoGenReport * enh: `_readonly ` for setReadonly * be 3.7 (#756) * be: nodeName * url-safe * md pdf * $cleanNumbern * be: text:关联记录>相关记录 * enh: 级联支持N2N字段 * entity-overview * Dockerfile * fix yj * enh: AutoApproval revoke * Update @rbv --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * feat: List cat ref (#757) * be: DataListCategory * fix: 审批返回上一步有分支节点时错误 * be: 清理备份错误提示 * oshi * Be 3.7 2 (#759) * Update MarkdownUtils.java * be: filter N2N:User * apiman pdf * Be 3.7 3 (#760) * fix * be: webcam * Update field-edit.html * be * Be 3.7 4 (#761) * Update system-cfg.html * ConcatIdFunction * Update FieldWriteback.java * be video * Update media-capturer.js * Update DataImportController.java * lang * be * Update DataImportController.java * Update RebuildWebConfigurer.java * flatpickr * Update rb-base.js * handleChange lazy * fix chart in datalist * Update submail.js * style * Be 3.7 5 (#762) * $hex2rgb * be: checkRefDataFilter * style: feeds * style: file-icon * fix: 记录转换 D>M+D * be install * be: tests * feat: form-formula {NOW} * fix: 日期短格式区间查询 * _readonly37 --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Be 3.7 6 (#764) * form: __LAB_FORMACTION_105, __LAB_FORMACTION_103 * __LAB_MINUTESTEP * fix: 字段更新清空时支持N2N * be: Installer.java * feat: $dropUpload * be: file RbPreview * fix * mde paste * be dropUpload * fix: 不触发 onClientProgress??? * Be 3.7 7 (#765) * fix: num input * style: NTEXT keep empty-line * media-capturer.js * fix: pdf 预览下载文件名不对 * feat: nform * Update KnownExceptionConverter.java * be * Be 3.7 8 (#766) * be NFORM * Update form-design.js * Update charts.js * Update FormsManager.java * Be 3.7 9 (#767) * feat: speclayout * feat: Gitee#I9UJ7N * feat: easyaction * useCode * Be 3.7 10 (#768) * v3.7-hide * lang * be: targetEntityMatchFields * fix: * _StartEntityTypeCode * be * Update README.md * Feat html5 report tinymce (#777) * f-3.8 * tinymce * be: template5 * Update @rbv * Check inst (#778) * bump lib * refactor * feat: stopPropagation * flatpickr * fix: time query * feat: class color * be --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Be easyaction2 (#781) * Update @rbv * open: nform * Update flatpickr.min.js * fix: class color * feat: word 相关项支持 * feat: html5 相关项 * Update report-templates.js * feat: open: __LAB_MATCHFIELDS * feat: class code * feat: ConcatArrayFunction * Update @rbv * be * Update @rbv * fix * Update @rbv * style * Update @rbv * Protable width (#784) * feat: series reset * col-resize * feat: user batch * be: IncreasingVar * be * enh:reports (#785) * feat: report CHECKBOX/CHECKBOX2 * open: _cfParent * enh: 多选字段显示不要边框 * fix:backspace select2 * enh: query maxlength * enh: FeedsSchedule relatedRecord * Update @rbv * File upload cam (#788) * enh: _captureType * bump lib * style: sop * enh: Share2 edit * feat: fp * Update @rbv * Fp details (#789) * enh: CreateFeed feedType * enh: fp for details * enh: stopPropagation=quickMode * enh: html5 recordIdMultiple * be: admin deep=3 * fix: ApprovalFields2Schema complement * Custom lang (#790) * feat: PREV_APPROVER_BACKED * feat; vertical38 * feat: _ProtectedAdmin * List group tab (#791) * feat: advListShowCategory-set * style * kill-session (#792) * be: MultipleSessions feat: kill-session h5 * Be template5 (#793) * fix: CVE * $tagStyle2 * Update rb-forms.append.js * Charts field filter (#796) * be * enh: extform search-filter; HANPINY * be exportReport * Update DataReportManager.java * 变更历史合并显示 * feat: class, ref: code-append * feat: axis filter * be: html5 preview * barcode decode * Update @rbv * Enh easyaction (#798) * enh-easyaction * enh: ValueConvertFunc * Update @rbv * Update FieldPrivileges.java * enh: excel 列表支持值转换(#SIZE不支持) * Update EasyExcelGenerator.java * Update @rbv * Update @rbv * be * rm PrivilegesGuardContextHolder * Update rb-forms.js * be: wrapReturn * 多表单适用新建 --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Update @rbv * be:3.8-1 (#799) * be * HowtoPointcut * style * fix SN * be-3.8-2 (#800) * be:weakMode * feat: calcFormulaBackend * feat: groupFields * be: sop * feat: 修改模版文件 * fix * style * Be 3.8 3 (#801) * be * NODE MIRROR * Update @rbv --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Be 3.8 4 (#802) * fix: 通过字段匹配没有 SERIES 字段 * fix: best form-layout * style * fix: sop * MysqldumpBin * style * Update application-dev.yml * Update @rbv * be-3.8-5 (#803) * Update ValueConvertFunc.java * pt fixedWidth * Update AdvFilterParser.java * YYY, MMM * Update @rbv * be: user-delete cascade * fix * RbvMissingController * ROUND * be * be-3.8-6 (#804) * bugfix * Update ValueConvertFunc.java * DECIMAL_ROUNDING, etc * lang * Update @rbv * Be 3.8 7 (#805) * be * style * fix * fix * Update @rbv * Update ValueConvertFunc.java * Be 3.8 8 (#806) * base64 * be * Update @rbv * fix CVE * lang * Be 3.8 9 (#807) * Update @rbv * codemirror hints * be NForms * feat: _expandLine * fix 单字段保存取消后仍有脏数据 * fix: 代码丢失??? * Be 3.8 10 (#808) * be * enh: 字段匹配支持N级 * enh: 补充自增编号顺序 * feat: FromtJS.Query * Be 3.8 10 (#809) * er * Be 3.8 10 (#810) * er * fix: 位置字段数据格式 * be * Be 3.8 11 (#811) * Update charts.js * be:表单回调 * -bosskey-show * report * fix * Update DataListWrapper.java * open:regRowButton * be * Update @rbv * Be 3.8 12 (#812) * be * be * Update DataExporter.java * fix fjs * be * Update @rbv * beta1 * Update README.md * Update media-capturer.js * Update @rbv * be: quick-filter * Update AdvFilterParser.java * Update rb-datalist.common.js * feat: 触发器执行日 * Update @rbv * style * 允许撤回、撤销审批 * Update MetadataGetting.java * AutoGenReport * Update form-design.js * style:sop --------- Co-authored-by: devezhao <zhaofang123@gmail.com> * Update ServerStatus.java --------- Co-authored-by: devezhao <zhaofang123@gmail.com>
1068 lines
35 KiB
Java
1068 lines
35 KiB
Java
/*!
|
||
Copyright (c) REBUILD <https://getrebuild.com/> and/or its owners. All rights reserved.
|
||
|
||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||
See LICENSE and COMMERCIAL in the project root for license information.
|
||
*/
|
||
/* global SelectReport TransformRich, FeedEditorDlg, LightTaskDlg, ApprovalProcessor, SopProcessor */
|
||
|
||
const wpc = window.__PageConfig || {}
|
||
|
||
const TYPE_DIVIDER = '$DIVIDER$'
|
||
const TYPE_REFFORM = '$REFFORM$'
|
||
|
||
//~~ 视图
|
||
class RbViewForm extends React.Component {
|
||
constructor(props) {
|
||
super(props)
|
||
this.state = { ...props }
|
||
|
||
this.onViewEditable = this.props.onViewEditable
|
||
if (this.onViewEditable) this.onViewEditable = wpc.onViewEditable !== false
|
||
if (window.__LAB_VIEWEDITABLE === false) this.onViewEditable = false
|
||
// temp for `saveSingleFieldValue`
|
||
this.__FormData = {}
|
||
}
|
||
|
||
render() {
|
||
return (
|
||
<RF>
|
||
{this.state.fjsAlertMessage}
|
||
<div className={`rbview-form form-layout ${window.__LAB_VERTICALLAYOUT && 'vertical38'}`} ref={(c) => (this._viewForm = c)}>
|
||
{this.state.formComponent}
|
||
</div>
|
||
</RF>
|
||
)
|
||
}
|
||
|
||
componentDidMount() {
|
||
$.get(`/app/${this.props.entity}/view-model?id=${this.props.id}`, (res) => {
|
||
// 有错误
|
||
if (res.error_code > 0 || !!res.data.error) {
|
||
const err = res.data.error || res.error_msg
|
||
this.renderViewError(err)
|
||
return
|
||
}
|
||
|
||
let hadApproval = res.data.hadApproval
|
||
let hadAlert = null
|
||
let hadSop = res.data.hadSop && rb.commercial > 1
|
||
if (wpc.type === 'DetailView') {
|
||
if (hadApproval === 2 || hadApproval === 10) {
|
||
if (window.RbViewPage) window.RbViewPage.setReadonly()
|
||
else $('.J_edit, .J_delete').remove()
|
||
|
||
hadAlert = <RbAlertBox message={hadApproval === 2 ? $L('主记录正在审批中,明细记录禁止操作') : $L('主记录已审批完成,明细记录禁止操作')} />
|
||
}
|
||
hadApproval = null
|
||
}
|
||
|
||
this.__ViewData = {}
|
||
this.__lastModified = res.data.lastModified || 0
|
||
if (res.data.onViewEditable === false) this.onViewEditable = false
|
||
|
||
const VFORM = (
|
||
<RF>
|
||
{hadAlert}
|
||
{hadApproval && <ApprovalProcessor id={this.props.id} entity={this.props.entity} />}
|
||
{hadSop && <SopProcessor id={this.props.id} entity={this.props.entity} />}
|
||
|
||
<div className="row">
|
||
{res.data.elements.map((item) => {
|
||
if (![TYPE_DIVIDER, TYPE_REFFORM].includes(item.field)) this.__ViewData[item.field] = item.value
|
||
if (item.field === TYPE_REFFORM) this.__hasRefform = true
|
||
item.$$$parent = this
|
||
return detectViewElement(item, this.props.entity)
|
||
})}
|
||
</div>
|
||
|
||
{this.renderCustomizedFormArea()}
|
||
</RF>
|
||
)
|
||
|
||
this.setState({ formComponent: VFORM }, () => {
|
||
this.hideLoading()
|
||
if (window.FrontJS) {
|
||
window.FrontJS.View._trigger('open', [res.data])
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
renderViewError(message) {
|
||
this.setState({ formComponent: _renderError(message) }, () => this.hideLoading())
|
||
$('.view-operating .view-action').empty()
|
||
}
|
||
|
||
renderCustomizedFormArea() {
|
||
let _FormArea
|
||
if (window._CustomizedForms) {
|
||
_FormArea = window._CustomizedForms.useFormArea(this.props.entity, this)
|
||
if (_FormArea) _FormArea = <div className="row">{React.cloneElement(_FormArea, { $$$parent: this })}</div>
|
||
}
|
||
return _FormArea || null
|
||
}
|
||
|
||
hideLoading() {
|
||
const ph = parent && parent.RbViewModal ? parent.RbViewModal.holder(this.state.id) : null
|
||
ph && ph.hideLoading()
|
||
}
|
||
|
||
showAgain(handle) {
|
||
this._checkDrityData(handle)
|
||
}
|
||
|
||
// 脏数据检查
|
||
_checkDrityData(handle) {
|
||
if (!this.__lastModified || !this.state.id) return
|
||
|
||
$.get(`/app/entity/extras/record-last-modified?id=${this.state.id}`, (res) => {
|
||
if (res.error_code === 0) {
|
||
if (res.data.lastModified !== this.__lastModified) {
|
||
handle && handle.showLoading()
|
||
setTimeout(() => location.reload(), 200)
|
||
}
|
||
} else if (res.error_msg === 'NO_EXISTS') {
|
||
this.renderViewError($L('记录已经不存在,可能已被其他用户删除'))
|
||
$('.view-operating').empty()
|
||
}
|
||
})
|
||
}
|
||
|
||
// @see RbForm in `rb-forms.js`
|
||
|
||
setFieldValue(field, value, error) {
|
||
this.__FormData[field] = { value: value, error: error }
|
||
// eslint-disable-next-line no-console
|
||
if (rb.env === 'dev') console.log('FV ...', JSON.stringify(this.__FormData))
|
||
}
|
||
|
||
setFieldUnchanged(field) {
|
||
delete this.__FormData[field]
|
||
// eslint-disable-next-line no-console
|
||
if (rb.env === 'dev') console.log('FV ...', JSON.stringify(this.__FormData))
|
||
}
|
||
|
||
// 保存单个字段值
|
||
saveSingleFieldValue(fieldComp) {
|
||
setTimeout(() => this._saveSingleFieldValue(fieldComp), 30)
|
||
}
|
||
|
||
_saveSingleFieldValue(fieldComp, weakMode) {
|
||
const fieldName = fieldComp.props.field
|
||
const fieldValue = this.__FormData[fieldName]
|
||
// Unchanged
|
||
if (!fieldValue) {
|
||
fieldComp.toggleEditMode(false)
|
||
return
|
||
}
|
||
if (fieldValue.error) return RbHighbar.create(fieldValue.error)
|
||
|
||
const data = {
|
||
metadata: { entity: this.props.entity, id: this.props.id },
|
||
[fieldName]: fieldValue.value,
|
||
}
|
||
|
||
const $btn = $(fieldComp._fieldText).find('.edit-oper .btn').button('loading')
|
||
let url = '/app/entity/record-save?singleField=true'
|
||
if (weakMode) url += '&weakMode=' + weakMode
|
||
$.post(url, JSON.stringify(data), (res) => {
|
||
$btn.button('reset')
|
||
|
||
if (res.error_code === 0) {
|
||
this.setFieldUnchanged(fieldName)
|
||
this.__ViewData[fieldName] = res.data[fieldName]
|
||
fieldComp.toggleEditMode(false, res.data[fieldName])
|
||
|
||
// 刷新列表
|
||
parent && parent.RbListPage && parent.RbListPage.reload(this.props.id, true)
|
||
|
||
// 刷新本页
|
||
if ((res.data && res.data.forceReload) || this.__hasRefform) {
|
||
setTimeout(() => RbViewPage.reload(), 200)
|
||
}
|
||
} else if (res.error_code === 499) {
|
||
// 重复记录
|
||
// eslint-disable-next-line react/jsx-no-undef
|
||
renderRbcomp(<RepeatedViewer entity={this.props.entity} data={res.data} />)
|
||
} else if (res.error_code === 497) {
|
||
// 弱校验
|
||
const that = this
|
||
const msg_id = res.error_msg.split('$$$$')
|
||
RbAlert.create(msg_id[0], {
|
||
onConfirm: function () {
|
||
this.hide()
|
||
that._saveSingleFieldValue(fieldComp, msg_id[1])
|
||
},
|
||
})
|
||
} else {
|
||
RbHighbar.error(res.error_msg)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
const detectViewElement = function (item, entity) {
|
||
if (!window.detectElement) throw 'detectElement undef'
|
||
item.onView = true
|
||
item.editMode = false
|
||
return window.detectElement(item, entity)
|
||
}
|
||
|
||
const _renderError = (message) => {
|
||
return (
|
||
<div className="alert alert-danger alert-icon mt-5 w-75" style={{ margin: '0 auto' }}>
|
||
<div className="icon">
|
||
<i className="zmdi zmdi-alert-triangle" />
|
||
</div>
|
||
<div className="message" dangerouslySetInnerHTML={{ __html: `<strong>${$L('抱歉!')}!</strong> ${message}` }} />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
// ~ 相关项列表
|
||
class RelatedList extends React.Component {
|
||
constructor(props) {
|
||
super(props)
|
||
this.state = { ...props }
|
||
|
||
// 相关配置
|
||
this.__searchSort = props.isDetail ? 'autoId:asc' : null
|
||
this.__searchKey = null
|
||
this.__pageNo = 1
|
||
|
||
this.__listExtraLink = null
|
||
this.__listClass = null
|
||
this.__listNoData = (
|
||
<div className="list-nodata">
|
||
<span className="zmdi zmdi-info-outline" />
|
||
<p>{$L('暂无数据')}</p>
|
||
</div>
|
||
)
|
||
|
||
// default:CARD
|
||
if (props.showViewMode) {
|
||
this.__viewModeKey = `RelatedListViewMode-${props.entity.split('.')[0]}`
|
||
let vm = $storage.get(this.__viewModeKey)
|
||
if (!vm) vm = props.defaultList ? 'LIST' : null
|
||
this.state.viewMode = vm || 'CARD'
|
||
}
|
||
}
|
||
|
||
render() {
|
||
const optionName = $random('vm-')
|
||
const isListView = this.props.showViewMode && this.state.viewMode === 'LIST'
|
||
|
||
return (
|
||
<div className={`related-list ${this.state.dataList || isListView ? '' : 'rb-loading rb-loading-active'}`}>
|
||
{!(this.state.dataList || isListView) && <RbSpinner />}
|
||
|
||
<div className="related-toolbar">
|
||
<div className="row">
|
||
<div className="col">
|
||
<div className="input-group input-search float-left">
|
||
<input className="form-control" type="text" placeholder={$L('快速查询')} maxLength="40" ref={(c) => (this._$quickSearch = c)} onKeyDown={(e) => e.keyCode === 13 && this.search()} />
|
||
<span className="input-group-btn">
|
||
<button className="btn btn-secondary" type="button" onClick={() => this.search()}>
|
||
<i className="icon zmdi zmdi-search" />
|
||
</button>
|
||
</span>
|
||
</div>
|
||
{this.__listExtraLink}
|
||
</div>
|
||
<div className="col text-right">
|
||
<div className="btn-group w-auto">
|
||
<button type="button" className="btn btn-link pr-0 text-right" data-toggle="dropdown" disabled={isListView}>
|
||
{this.state.sortDisplayText || $L('默认排序')} <i className="icon zmdi zmdi-chevron-down up-1" />
|
||
</button>
|
||
{this.renderSorts()}
|
||
</div>
|
||
|
||
{this.props.showViewMode && (
|
||
<div className="btn-group btn-group-toggle w-auto ml-3 switch-view-mode">
|
||
<label className={`btn btn-light ${this.state.viewMode === 'LIST' ? '' : 'active'}`} title={$L('卡片视图')}>
|
||
<input type="radio" name={optionName} value="CARD" checked={this.state.viewMode !== 'LIST'} onChange={(e) => this.switchViewMode(e)} />
|
||
<i className="icon mdi mdi-view-agenda-outline" />
|
||
</label>
|
||
<label className={`btn btn-light ${this.state.viewMode === 'LIST' ? 'active' : ''}`} title={$L('列表视图')}>
|
||
<input type="radio" name={optionName} value="LIST" checked={this.state.viewMode === 'LIST'} onChange={(e) => this.switchViewMode(e)} />
|
||
<i className="icon mdi mdi-view-module-outline fs-22 down-1" />
|
||
</label>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{this.renderData()}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
renderSorts() {
|
||
return (
|
||
<div className="dropdown-menu dropdown-menu-right" x-placement="bottom-end">
|
||
<a className="dropdown-item" data-sort="modifiedOn:desc" onClick={(e) => this.search(e)}>
|
||
{$L('最近修改')}
|
||
</a>
|
||
<a className="dropdown-item" data-sort="createdOn:desc" onClick={(e) => this.search(e)}>
|
||
{$L('最近创建')}
|
||
</a>
|
||
<a className="dropdown-item" data-sort="createdOn" onClick={(e) => this.search(e)}>
|
||
{$L('最早创建')}
|
||
</a>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
renderData() {
|
||
return (
|
||
<RF>
|
||
{this.state.dataList && this.state.dataList.length === 0 && this.__listNoData}
|
||
|
||
{this.state.dataList && this.state.dataList.length > 0 && (
|
||
<div className={this.__listClass || ''}>
|
||
{(this.state.dataList || []).map((item) => {
|
||
return this.renderItem(item)
|
||
})}
|
||
</div>
|
||
)}
|
||
|
||
{this.state.showMore && (
|
||
<div className="text-center mt-2 pb-2">
|
||
<button type="button" className="btn btn-link" onClick={() => this.fetchData(1)}>
|
||
{$L('显示更多')}
|
||
</button>
|
||
</div>
|
||
)}
|
||
</RF>
|
||
)
|
||
}
|
||
|
||
renderItem(item) {
|
||
return <div>{JSON.stringify(item)}</div>
|
||
}
|
||
|
||
componentDidMount() {
|
||
this.fetchData()
|
||
}
|
||
|
||
fetchData(append) {
|
||
this.__pageNo = this.__pageNo || 1
|
||
if (append) this.__pageNo += append
|
||
|
||
const pageSize = 20
|
||
const url = `/project/tasks/related-list?pageNo=${this.__pageNo}&pageSize=${pageSize}&sort=${this.__searchSort || ''}&related=${this.props.mainid}`
|
||
$.get(url, (res) => {
|
||
if (res.error_code !== 0) return RbHighbar.error(res.error_msg)
|
||
|
||
const data = (res.data || {}).data || []
|
||
const list = append ? (this.state.dataList || []).concat(data) : data
|
||
this.setState({ dataList: list, showMore: data.length >= pageSize })
|
||
})
|
||
}
|
||
|
||
search(e) {
|
||
let sort = null
|
||
if (e && e.currentTarget) {
|
||
sort = $(e.currentTarget).data('sort')
|
||
this.setState({ sortDisplayText: $(e.currentTarget).text() })
|
||
}
|
||
|
||
this.__searchSort = sort || this.__searchSort
|
||
this.__searchKey = $(this._$quickSearch).val() || ''
|
||
this.__pageNo = 1
|
||
|
||
this.fetchData()
|
||
}
|
||
|
||
switchViewMode(e, call) {
|
||
const mode = e.currentTarget.value
|
||
this.setState({ viewMode: mode }, () => {
|
||
$storage.set(this.__viewModeKey, mode)
|
||
typeof call === 'function' && call(mode)
|
||
})
|
||
}
|
||
}
|
||
|
||
const APPROVAL_STATE_CLAZZs = {
|
||
2: [$L('审批中'), 'warning'],
|
||
10: [$L('通过'), 'success'],
|
||
11: [$L('驳回'), 'danger'],
|
||
}
|
||
// ~ 业务实体相关项列表
|
||
class EntityRelatedList extends RelatedList {
|
||
constructor(props) {
|
||
super(props)
|
||
this.state.viewOpens = {}
|
||
this.state.viewComponents = {}
|
||
|
||
this.__entity = props.entity.split('.')[0]
|
||
|
||
const openListUrl = `${rb.baseUrl}/app/${this.__entity}/list?via=${this.props.mainid}:${this.props.entity}`
|
||
this.__listExtraLink = (
|
||
<a className="btn btn-light w-auto" href={openListUrl} target="_blank" title={$L('在新页面打开')}>
|
||
<i className="icon zmdi zmdi-open-in-new" />
|
||
</a>
|
||
)
|
||
}
|
||
|
||
renderItem(item) {
|
||
const astate = APPROVAL_STATE_CLAZZs[item[3]]
|
||
return (
|
||
<div key={item[0]} className={`card ${this.state.viewOpens[item[0]] ? 'active' : ''}`} ref={`item-${item[0]}`}>
|
||
<div className="row header-title" onClick={() => this._toggleInsideView(item[0])}>
|
||
<div className="col-9">
|
||
<a href={`#!/View/${this.__entity}/${item[0]}`} onClick={(e) => this._handleView(e)} title={$L('打开')}>
|
||
{item[1]}
|
||
</a>
|
||
</div>
|
||
<div className="col-3 record-meta">
|
||
{item[4] && (
|
||
<a className="edit" onClick={(e) => this._handleEdit(e, item[0])} title={$L('编辑')}>
|
||
<i className="icon zmdi zmdi-edit" />
|
||
</a>
|
||
)}
|
||
|
||
{astate && <span className={`badge badge-pill badge-${astate[1]}`}>{astate[0]}</span>}
|
||
|
||
<span className="fs-12 text-muted" title={`${$L('修改时间')} ${item[2]}`}>
|
||
{$fromNow(item[2])}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div className={`rbview-form form-layout inside ${window.__LAB_VERTICALLAYOUT && 'vertical38'}`}>{this.state.viewComponents[item[0]] || <RbSpinner fully={true} />}</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
// 显示模式支持: 卡片/列表
|
||
|
||
switchViewMode(e) {
|
||
super.switchViewMode(e, (mode) => {
|
||
// 加载卡片数据
|
||
mode === 'CARD' && this.__fetchData !== true && this.fetchData()
|
||
})
|
||
}
|
||
|
||
renderData() {
|
||
if (this.state.viewMode === 'LIST') {
|
||
// if (!this.state.dataList) this.setState({ dataList: [] }) // Hide loading
|
||
return <EntityRelatedList2 $$$parent={this} ref={(c) => (this._EntityRelatedList2 = c)} />
|
||
} else {
|
||
return super.renderData()
|
||
}
|
||
}
|
||
|
||
search(e) {
|
||
if (this._EntityRelatedList2) {
|
||
this.__searchKey = $(this._$quickSearch).val() || ''
|
||
this._EntityRelatedList2.search(this.__searchKey)
|
||
} else {
|
||
super.search(e)
|
||
}
|
||
}
|
||
|
||
fetchData(append) {
|
||
if (this.state.viewMode === 'LIST') return
|
||
else this.__fetchData = true
|
||
|
||
this.__pageNo = this.__pageNo || 1
|
||
if (append) this.__pageNo += append
|
||
|
||
const pageSize = 20
|
||
const url = `/app/entity/related-list?mainid=${this.props.mainid}&related=${this.props.entity}&pageNo=${this.__pageNo}&pageSize=${pageSize}&sort=${this.__searchSort || ''}&q=${$encode(
|
||
this.__searchKey
|
||
)}`
|
||
|
||
$.get(url, (res) => {
|
||
if (res.error_code !== 0) return RbHighbar.error(res.error_msg)
|
||
|
||
const data = res.data.data || []
|
||
const list = append ? (this.state.dataList || []).concat(data) : data
|
||
|
||
this.setState({ dataList: list, showMore: data.length >= pageSize }, () => {
|
||
if (this.props.autoExpand) {
|
||
data.forEach((item) => {
|
||
// eslint-disable-next-line react/no-string-refs
|
||
const $H = $(this.refs[`item-${item[0]}`]).find('.header-title')
|
||
if ($H.length > 0 && !$H.parent().hasClass('active')) $H[0].click()
|
||
})
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
_handleEdit(e, id) {
|
||
$stopEvent(e, true)
|
||
RbFormModal.create({ id: id, entity: this.__entity, title: $L('编辑%s', this.props.entity2[0]), icon: this.props.entity2[1] }, true)
|
||
}
|
||
|
||
_handleView(e) {
|
||
$stopEvent(e, true)
|
||
RbViewPage.clickView(e.currentTarget)
|
||
}
|
||
|
||
_toggleInsideView(id) {
|
||
const viewOpens = this.state.viewOpens
|
||
viewOpens[id] = !viewOpens[id]
|
||
this.setState({ viewOpens: viewOpens })
|
||
|
||
// 加载视图
|
||
const viewComponents = this.state.viewComponents
|
||
if (!viewComponents[id]) {
|
||
$.get(`/app/${this.__entity}/view-model?id=${id}`, (res) => {
|
||
if (res.error_code > 0 || !!res.data.error) {
|
||
viewComponents[id] = _renderError(res.data.error || res.error_msg)
|
||
} else {
|
||
viewComponents[id] = (
|
||
<div className="row">
|
||
{res.data.elements.map((item) => {
|
||
item.$$$parent = this
|
||
return detectViewElement(item)
|
||
})}
|
||
</div>
|
||
)
|
||
}
|
||
this.setState({ viewComponents: viewComponents })
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
// 列表模式
|
||
class EntityRelatedList2 extends React.Component {
|
||
constructor(props) {
|
||
super(props)
|
||
this.state = {}
|
||
}
|
||
|
||
render() {
|
||
const p = this.props.$$$parent
|
||
const related = `related:${p.props.entity}:${p.props.mainid}`
|
||
|
||
return (
|
||
<div className="card-table">
|
||
<div className="dataTables_wrapper container-fluid">
|
||
<div className="rb-loading rb-loading-active data-list" ref={(c) => (this._$wrapper2 = c)}>
|
||
{this.state.listConfig && <RbList config={this.state.listConfig} protocolFilter={related} $wrapper={this._$wrapper2} unpin ref={(c) => (this._RbList = c)} />}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
componentDidMount() {
|
||
$.get(`/app/entity/related-list-config?entity=${this.props.$$$parent.__entity}`, (res) => {
|
||
if (res.error_code === 0) {
|
||
this.setState({ listConfig: { ...res.data } })
|
||
}
|
||
})
|
||
}
|
||
|
||
search(q) {
|
||
if (!this._RbList) return
|
||
|
||
const s = {
|
||
entity: this.props.$$$parent.__entity,
|
||
type: 'QUICK',
|
||
values: { 1: q },
|
||
}
|
||
this._RbList.search(s)
|
||
}
|
||
}
|
||
|
||
class MixRelatedList extends React.Component {
|
||
state = { ...this.props }
|
||
|
||
render() {
|
||
const entity = this.props.entity.split('.')[0]
|
||
if (entity === 'Feeds') {
|
||
// eslint-disable-next-line react/jsx-no-undef
|
||
return <LightFeedsList {...this.props} fetchNow />
|
||
} else if (entity === 'ProjectTask') {
|
||
// eslint-disable-next-line react/jsx-no-undef
|
||
return <LightTaskList {...this.props} fetchNow />
|
||
} else if (entity === 'Attachment') {
|
||
// eslint-disable-next-line react/jsx-no-undef
|
||
return <LightAttachmentList {...this.props} fetchNow />
|
||
} else {
|
||
return <EntityRelatedList {...this.props} showViewMode />
|
||
}
|
||
}
|
||
}
|
||
|
||
// for view-addons.js
|
||
// eslint-disable-next-line no-unused-vars
|
||
var _showFilterForAddons = function (opt) {
|
||
renderRbcomp(<AdvFilter entity={opt.entity} filter={opt.filter} confirm={opt.onConfirm} title={$L('附加过滤条件')} inModal canNoFilters />)
|
||
}
|
||
|
||
// 视图页操作类
|
||
const RbViewPage = {
|
||
_RbViewForm: null,
|
||
|
||
/**
|
||
* @param {*} id Record ID
|
||
* @param {*} entity array:[Name, Label, Icon]
|
||
* @param {*} ep Privileges of this entity
|
||
*/
|
||
init(id, entity, ep) {
|
||
this.__id = id
|
||
this.__entity = entity
|
||
this.__ep = ep
|
||
|
||
renderRbcomp(<RbViewForm entity={entity[0]} id={id} onViewEditable={ep && ep.U} />, 'tab-rbview', function () {
|
||
RbViewPage._RbViewForm = this
|
||
setTimeout(() => $('.view-body.loading').removeClass('loading'), 100)
|
||
})
|
||
|
||
$('.J_close').on('click', () => this.hide())
|
||
$('.J_reload').on('click', () => this.reload())
|
||
$('.J_newpage').attr({ target: '_blank', href: location.href })
|
||
|
||
if (parent && parent.RbListPage) $('.J_newpage').removeClass('hide')
|
||
if (parent && parent.RbViewModal && parent.RbViewModal.mode === 2) $('.J_close').remove()
|
||
|
||
const that = this
|
||
|
||
$('.J_delete').on('click', function () {
|
||
if ($(this).attr('disabled')) return
|
||
|
||
const needEntity = wpc.type === 'DetailList' || wpc.type === 'DetailView' ? null : entity[0]
|
||
renderRbcomp(
|
||
<DeleteConfirm
|
||
id={that.__id}
|
||
entity={needEntity}
|
||
deleteAfter={(deleted) => {
|
||
if (deleted > 0) {
|
||
// 刷新主视图
|
||
parent && parent.RbViewModal && parent.RbViewModal.currentHolder(true)
|
||
that.hide(true)
|
||
}
|
||
}}
|
||
/>
|
||
)
|
||
})
|
||
|
||
$('.J_edit').on('click', () => {
|
||
RbFormModal.create({ id: id, title: $L('编辑%s', entity[1]), entity: entity[0], icon: entity[2] }, true)
|
||
})
|
||
$('.J_assign').on('click', () => DlgAssign.create({ entity: entity[0], ids: [id] }))
|
||
$('.J_share').on('click', () => DlgShare.create({ entity: entity[0], ids: [id] }))
|
||
$('.J_report').on('click', () => SelectReport.create(entity[0], id))
|
||
$('.J_add-details>a').on('click', function () {
|
||
const iv = { $MAINID$: id }
|
||
const $this = $(this)
|
||
RbFormModal.create({ title: $L('添加%s', $this.data('label')), entity: $this.data('entity'), icon: $this.data('icon'), initialValue: iv, _nextAddDetail: true })
|
||
})
|
||
|
||
if (wpc.transformTos && wpc.transformTos.length > 0) {
|
||
this.initTransform(wpc.transformTos)
|
||
$('.J_transform').removeClass('hide')
|
||
} else {
|
||
$('.J_transform').remove()
|
||
}
|
||
|
||
// Privileges
|
||
if (ep) {
|
||
if (ep.D === false) $('.J_delete').remove()
|
||
if (ep.U === false) $('.J_edit, .J_add-detail, .J_add-details').remove()
|
||
if (ep.A !== true) $('.J_assign').remove()
|
||
if (ep.S !== true) $('.J_share').remove()
|
||
}
|
||
|
||
// Clean buttons
|
||
that._cleanViewActionButton()
|
||
|
||
that.initRecordMeta()
|
||
that.initHistory()
|
||
|
||
setTimeout(() => {
|
||
if (window.parent && window.parent.tourStarted) return
|
||
typeof window.startTour === 'function' && window.startTour()
|
||
}, 1200)
|
||
},
|
||
|
||
// 元数据
|
||
initRecordMeta() {
|
||
$.get(`/app/entity/extras/record-meta?id=${this.__id}`, (res) => {
|
||
// 如果出错就清空操作区
|
||
if (res.error_code !== 0) {
|
||
$('.view-operating').empty()
|
||
return
|
||
}
|
||
|
||
const that = this
|
||
for (let k in res.data) {
|
||
const v = res.data[k]
|
||
if (!v) continue
|
||
const $el = $(`.J_${k}`)
|
||
if ($el.length === 0) continue
|
||
|
||
if (k === 'owningUser') {
|
||
renderRbcomp(<UserShow id={v[0]} name={v[1]} showName={true} deptName={v[2]} onClick={() => this._clickViewUser(v[0])} />, $el[0])
|
||
} else if (k === 'sharingList') {
|
||
const $list = $('<ul class="list-unstyled list-inline mb-0"></ul>').appendTo($('.J_sharingList').empty())
|
||
$(v).each(function () {
|
||
const _this = this
|
||
const $item = $('<li class="list-inline-item"></li>').appendTo($list)
|
||
renderRbcomp(<UserShow id={_this[0]} name={_this[1]} onClick={() => that._clickViewUser(_this[0])} />, $item[0])
|
||
})
|
||
|
||
if (this.__ep && this.__ep.S === true) {
|
||
const $op = $('<li class="list-inline-item"></li>').appendTo($list)[0]
|
||
if (v.length === 0) {
|
||
renderRbcomp(
|
||
<UserShow
|
||
name={$L('添加共享')}
|
||
icon="zmdi zmdi-plus"
|
||
onClick={() => {
|
||
$('.J_share').trigger('click')
|
||
}}
|
||
/>,
|
||
$op
|
||
)
|
||
} else {
|
||
renderRbcomp(<UserShow name={$L('管理共享用户')} icon="zmdi zmdi-more" onClick={() => DlgShareManager.create(this.__id)} />, $op)
|
||
}
|
||
} else if (v.length > 0) {
|
||
const $op = $('<li class="list-inline-item"></li>').appendTo($list)[0]
|
||
renderRbcomp(<UserShow name={$L('查看共享用户')} icon="zmdi zmdi-more" onClick={() => DlgShareManager.create(this.__id, false)} />, $op)
|
||
} else {
|
||
$('.J_sharingList').parent().remove()
|
||
}
|
||
} else if (k === 'createdOn' || k === 'modifiedOn') {
|
||
renderRbcomp(<DateShow date={v} />, $el[0])
|
||
} else {
|
||
$(`<span>${v}</span>`).appendTo($el.empty())
|
||
}
|
||
}
|
||
|
||
// PlainEntity ?
|
||
if (!res.data.owningUser) $('.view-user').remove()
|
||
})
|
||
},
|
||
|
||
// 修改历史
|
||
initHistory() {
|
||
const $into = $('.view-history .view-history-items')
|
||
if ($into.length === 0) return
|
||
|
||
$.get(`/app/entity/extras/record-history?id=${this.__id}`, (res) => {
|
||
if (res.error_code !== 0) return
|
||
|
||
// v3.8 合并显示
|
||
let _data = []
|
||
let prev
|
||
res.data.forEach((item) => {
|
||
// 同样的合并
|
||
if (prev && prev.revisionType === item.revisionType && prev.revisionBy[0] === item.revisionBy[0]) {
|
||
let diff = $moment(item.revisionOn).diff($moment(prev.revisionOn), 'seconds')
|
||
if (Math.abs(diff) < 30) {
|
||
prev._merged = (prev._merged || 1) + 1
|
||
return
|
||
}
|
||
}
|
||
_data.push(item)
|
||
prev = item
|
||
})
|
||
|
||
$into.empty()
|
||
_data.forEach((item, idx) => {
|
||
let content = $L('**%s** 由 %s %s', $fromNow(item.revisionOn), item.revisionBy[1], item.revisionType)
|
||
if (item._merged > 1) content += ` <sup>${item._merged}</sup>`
|
||
|
||
const $item = $(`<li>${content}</li>`).appendTo($into)
|
||
$item.find('b:eq(0)').attr('title', item.revisionOn)
|
||
if (idx > 9) $item.addClass('hide')
|
||
})
|
||
|
||
if (_data.length > 10) {
|
||
$into.after(`<a href="javascript:;" class="J_mores">${$L('显示更多')}</a>`)
|
||
$('.view-history .J_mores').on('click', function () {
|
||
$into.find('li.hide').removeClass('hide')
|
||
$(this).addClass('hide')
|
||
})
|
||
} else if (_data.length === 0) {
|
||
$(`<li>${$L('无')}</li>`).appendTo($into)
|
||
}
|
||
|
||
// v3.6
|
||
$('.view-history.invisible2').removeClass('invisible2')
|
||
})
|
||
},
|
||
|
||
// 相关项
|
||
|
||
// 列表
|
||
initVTabs(config) {
|
||
const that = this
|
||
that.__vtabEntities = []
|
||
$(config).each(function () {
|
||
const configThat = this
|
||
const entity = this.entity // Entity.Field
|
||
that.__vtabEntities.push(entity)
|
||
const tabId = `tab-${entity.replace('.', '--')}` // `.` is JS keyword
|
||
|
||
const listProps = {
|
||
entity: entity,
|
||
entity2: [configThat.entityLabel, configThat.icon],
|
||
mainid: that.__id,
|
||
autoExpand: $isTrue(wpc.viewTabsAutoExpand),
|
||
defaultList: $isTrue(wpc.viewTabsDefaultList),
|
||
isDetail: !!this.showAt2,
|
||
}
|
||
|
||
// v3.4 明细显示在下方
|
||
if (this.showAt2 === 2) {
|
||
const $pane = $(`<div class="tab-pane-bottom"><h5><i class="zmdi zmdi-${this.icon}"></i>${this.entityLabel}</h5><div id="${tabId}"></div></div>`).appendTo('.tab-content-bottom')
|
||
$(`<a class="icon zmdi zmdi-chevron-down" title="${$L('展开/收起')}"></a>`)
|
||
.appendTo($pane.find('h5'))
|
||
.on('click', () => $pane.toggleClass('toggle-hide'))
|
||
renderRbcomp(<MixRelatedList {...listProps} />, tabId)
|
||
return
|
||
}
|
||
|
||
const $tabNav = $(
|
||
`<li class="nav-item ${$isTrue(wpc.viewTabsAutoHide) && 'hide'}"><a class="nav-link" href="#${tabId}" data-toggle="tab" title="${this.entityLabel}">${this.entityLabel}</a></li>`
|
||
).appendTo('.nav-tabs')
|
||
const $tabPane = $(`<div class="tab-pane" id="${tabId}"></div>`).appendTo('.tab-content')
|
||
$tabNav.find('a').on('click', function () {
|
||
$tabPane.find('.related-list').length === 0 && renderRbcomp(<MixRelatedList {...listProps} />, $tabPane)
|
||
})
|
||
})
|
||
this.updateVTabs()
|
||
|
||
// for Admin
|
||
if (rb.isAdminUser) {
|
||
$('.J_view-addons').on('click', function () {
|
||
const type = $(this).data('type')
|
||
RbModal.create(`/p/admin/metadata/view-addons?entity=${that.__entity[0]}&type=${type}`, type === 'TAB' ? $L('配置显示项') : $L('配置新建项'))
|
||
})
|
||
}
|
||
},
|
||
|
||
// 记录数量
|
||
updateVTabs(specEntities) {
|
||
specEntities = specEntities || this.__vtabEntities
|
||
if (!specEntities || specEntities.length === 0) return
|
||
|
||
$.get(`/app/entity/related-counts?mainid=${this.__id}&relateds=${specEntities.join(',')}`, function (res) {
|
||
for (let k in res.data || {}) {
|
||
if (~~res.data[k] > 0) {
|
||
const tabId = `#tab-${k.replace('.', '--')}`
|
||
const $tabNav = $(`.nav-tabs a[href="${tabId}"]`)
|
||
if ($tabNav[0]) {
|
||
$tabNav.parent().removeClass('hide')
|
||
|
||
if ($tabNav.find('.badge').length > 0) $tabNav.find('.badge').text(res.data[k])
|
||
else $(`<span class="badge badge-pill badge-primary">${res.data[k]}</span>`).appendTo($tabNav)
|
||
} else {
|
||
const $tabLine = $(tabId)
|
||
if ($tabLine[0]) {
|
||
let $span = $tabLine.prev().find('span')
|
||
if (!$span[0]) $span = $('<span></span>').appendTo($tabLine.prev())
|
||
$span.text(` (${res.data[k]})`)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 新建相关
|
||
initVAdds(config) {
|
||
const that = this
|
||
$(config).each(function () {
|
||
const item = this
|
||
const $item = $(`<a class="dropdown-item"><i class="icon zmdi zmdi-${item.icon}"></i>${item.entityLabel}</a>`)
|
||
$item.on('click', function () {
|
||
if (item.entity === 'Feeds.relatedRecord') {
|
||
const data = {
|
||
type: 2,
|
||
relatedRecord: { id: that.__id, entity: that.__entity[0], text: `@${that.__id.toUpperCase()}` },
|
||
}
|
||
renderRbcomp(
|
||
<FeedEditorDlg
|
||
{...data}
|
||
call={() => {
|
||
RbHighbar.success($L('保存成功'))
|
||
setTimeout(() => that.reload(), 100)
|
||
}}
|
||
/>
|
||
)
|
||
} else if (item.entity === 'ProjectTask.relatedRecord') {
|
||
renderRbcomp(
|
||
<LightTaskDlg
|
||
relatedRecord={that.__id}
|
||
call={() => {
|
||
RbHighbar.success($L('保存成功'))
|
||
setTimeout(() => that.reload(), 100)
|
||
}}
|
||
/>
|
||
)
|
||
} else {
|
||
const iv = {}
|
||
const entity = item.entity.split('.')
|
||
if (entity.length > 1) iv[entity[1]] = that.__id
|
||
else iv[`&${that.__entity[0]}`] = that.__id
|
||
|
||
RbFormModal.create({ title: $L('新建%s', item._entityLabel || item.entityLabel), entity: entity[0], icon: item.icon, initialValue: iv })
|
||
}
|
||
})
|
||
|
||
$('.J_adds .dropdown-divider').before($item)
|
||
})
|
||
},
|
||
|
||
// 转换
|
||
initTransform(config) {
|
||
const that = this
|
||
config.forEach((item) => {
|
||
const $item = $(`<a class="dropdown-item"><i class="icon zmdi zmdi-${item.icon}"></i>${item.transName || item.entityLabel}</a>`)
|
||
|
||
const entity = item.entity.split('.')
|
||
$item.on('click', () => {
|
||
let _TransformRich
|
||
|
||
if (item.previewMode) {
|
||
const previewid = `${item.transid}.${that.__id}`
|
||
if (item.mainEntity) {
|
||
RbAlert.create(<TransformRich {...item} ref={(c) => (_TransformRich = c)} />, {
|
||
icon: 'info-outline',
|
||
onConfirm: function () {
|
||
const mainid = _TransformRich.getMainId()
|
||
if (mainid === false) return
|
||
|
||
this.hide()
|
||
RbFormModal.create({ title: $L('新建%s', item.entityLabel), entity: entity[0], icon: item.icon, previewid: `${previewid}.${mainid}` }, true)
|
||
},
|
||
})
|
||
} else {
|
||
RbFormModal.create({ title: $L('新建%s', item.entityLabel), entity: entity[0], icon: item.icon, previewid: previewid }, true)
|
||
}
|
||
|
||
// end: previewMode
|
||
} else {
|
||
RbAlert.create(<TransformRich {...item} ref={(c) => (_TransformRich = c)} />, {
|
||
tabIndex: 1,
|
||
onConfirm: function () {
|
||
const mainid = _TransformRich.getMainId()
|
||
if (mainid === false) return
|
||
|
||
this.disabled(true, true)
|
||
$.post(`/app/entity/extras/transform?transid=${item.transid}&source=${that.__id}&mainid=${mainid === true ? '' : mainid}`, (res) => {
|
||
if (res.error_code === 0) {
|
||
this.hide(true)
|
||
setTimeout(() => that.clickView(`#!/View/${item.entity}/${res.data}`), 200)
|
||
} else {
|
||
this.disabled()
|
||
res.error_code === 400 ? RbHighbar.create(res.error_msg) : RbHighbar.error(res.error_msg)
|
||
}
|
||
})
|
||
},
|
||
})
|
||
}
|
||
})
|
||
|
||
$('.J_transform .dropdown-divider').before($item)
|
||
})
|
||
},
|
||
|
||
// 通过父级页面打开
|
||
clickView(target) {
|
||
// `#!/View/{entity}/{id}`
|
||
const viewUrl = typeof target === 'string' ? target : $(target).attr('href')
|
||
if (!viewUrl) {
|
||
console.warn('Bad view target : ', target)
|
||
return
|
||
}
|
||
|
||
const urlSpec = viewUrl.split('/')
|
||
if (parent && parent.RbViewModal) {
|
||
parent.RbViewModal.create({ entity: urlSpec[2], id: urlSpec[3] }, true)
|
||
} else {
|
||
// window.open(`${rb.baseUrl}/app/redirect?id=${urlSpec[3]}&type=newtab`)
|
||
window.open(`${rb.baseUrl}/app/${urlSpec[2]}/view/${urlSpec[3]}`)
|
||
}
|
||
return false
|
||
},
|
||
|
||
_clickViewUser(id) {
|
||
return this.clickView(`#!/View/User/${id}`)
|
||
},
|
||
|
||
// 清理操作按钮
|
||
_cleanViewActionButton() {
|
||
$setTimeout(
|
||
() => {
|
||
$cleanMenu('.view-action .J_mores')
|
||
$cleanMenu('.view-action .J_adds')
|
||
$cleanMenu('.view-action .J_transform')
|
||
$('.view-action .col-lg-6').each(function () {
|
||
if ($(this).children().length === 0) $(this).remove()
|
||
})
|
||
if ($('.view-action').children().length === 0) $('.view-action').addClass('mt-0').empty()
|
||
// v3.6
|
||
$('.view-action.invisible2').removeClass('invisible2')
|
||
},
|
||
20,
|
||
'_cleanViewActionButton'
|
||
)
|
||
},
|
||
|
||
// 隐藏
|
||
hide(reload) {
|
||
if (parent && parent !== window) {
|
||
parent && parent.RbViewModal && parent.RbViewModal.holder(this.__id, 'HIDE')
|
||
if (reload === true) {
|
||
if (parent.RbListPage) parent.RbListPage.reload()
|
||
else setTimeout(() => parent.location.reload(), 200)
|
||
}
|
||
// v3.4
|
||
if (parent.location.href.includes('/app/entity/view')) parent.window.close()
|
||
} else {
|
||
window.close() // Maybe unclose
|
||
}
|
||
},
|
||
|
||
// 重新加載
|
||
reload() {
|
||
parent && parent.RbViewModal && parent.RbViewModal.holder(this.__id, 'LOADING')
|
||
setTimeout(() => location.reload(), 20)
|
||
},
|
||
|
||
// 记录只读
|
||
setReadonly() {
|
||
$(this._RbViewForm._viewForm).addClass('readonly')
|
||
$('.J_edit, .J_delete, .J_add-detail, .J_add-details').remove()
|
||
this._cleanViewActionButton()
|
||
},
|
||
}
|
||
|
||
// init
|
||
$(document).ready(function () {
|
||
// 回退按钮
|
||
if ($urlp('back') === 'auto' && parent && parent.RbViewModal) {
|
||
$('.J_back')
|
||
.removeClass('hide')
|
||
.on('click', () => history.back())
|
||
}
|
||
// Dock
|
||
if (parent && parent.location.href.includes('/app/entity/view')) {
|
||
$('.view-header').remove()
|
||
}
|
||
|
||
// iframe 点击穿透
|
||
if (parent) {
|
||
$(document).on('click', () => parent.$(parent.document).trigger('_clickEventHandler'))
|
||
window._clickEventHandler = () => $(document).trigger('click')
|
||
}
|
||
|
||
if (wpc.entity) {
|
||
RbViewPage.init(wpc.recordId, wpc.entity, wpc.privileges)
|
||
if (wpc.viewTabs) RbViewPage.initVTabs(wpc.viewTabs)
|
||
if (wpc.viewAdds) RbViewPage.initVAdds(wpc.viewAdds)
|
||
}
|
||
})
|