* remove biz feature files from the open source version.
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
.content-row {display: flex; flex-direction: row; padding: 8px 0px;}
|
||||
.input-label {width: 120px; flex-shrink: 0; padding: 6px 12px; text-align: right;}
|
||||
.input {flex-grow: 1;}
|
||||
.main-header {border-bottom-color: #E6EAF1;}
|
||||
@@ -1,11 +0,0 @@
|
||||
(function()
|
||||
{
|
||||
const inputs = [...Array.from(document.querySelectorAll('input')), ...Array.from(document.querySelectorAll('textarea'))];
|
||||
inputs.forEach(element => {
|
||||
const displayElement = document.getElementById(element.name + 'Display');
|
||||
if(!displayElement) return;
|
||||
element.addEventListener('input', () => {
|
||||
displayElement.innerText = element.value;
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The ai createPrompt view file of ai module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wenrui LI <liwenrui@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.lite.html.php';?>
|
||||
<?php js::set('requiredFields', $config->ai->createprompt->requiredFields);?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $this->lang->ai->prompts->create;?></h2>
|
||||
</div>
|
||||
<form method="post" class="main-form form-ajax" target="hiddenwin">
|
||||
<table class="table table-form">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="w-80px"><?php echo $this->lang->ai->prompts->name;?></th>
|
||||
<td><?php echo html::input('name', '', "class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="w-80px"><?php echo $this->lang->ai->prompts->description;?></th>
|
||||
<td><?php echo html::textarea('desc', '', "rows='6' class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="text-center form-actions">
|
||||
<?php echo html::submitButton($this->lang->ai->nextStep, 'disabled', 'btn btn-wide btn-primary disabled');?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function() {
|
||||
$('input[name="name"]').on('input', function()
|
||||
{
|
||||
if($(this).val().length > 0)
|
||||
{
|
||||
$('button[type="submit"]').removeClass('disabled').removeAttr('disabled');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('button[type="submit"]').addClass('disabled').attr('disabled', 'disabled');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function gotoPrompt(id)
|
||||
{
|
||||
parent.location.href = <?php echo commonModel::hasPriv('ai', 'promptassignrole') ? "createLink('ai', 'promptassignrole', 'prompt='" : "createLink('ai', 'promptview', 'id='";?> + id);
|
||||
}
|
||||
</script>
|
||||
<?php include '../../common/view/footer.lite.html.php';?>
|
||||
@@ -1,283 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The ai prompt role assign view file of ai module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wenrui LI <liwenrui@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<style>
|
||||
.center-wrapper {display: flex; justify-content: center; height: 100%;}
|
||||
.center-content {min-width: 800px; height: 100%; display: flex; flex-direction: column;}
|
||||
.content-row {display: flex; flex-direction: row; padding: 8px 0px;}
|
||||
.input-label {width: 120px; padding: 6px 12px; text-align: right;}
|
||||
.input {flex-grow: 1;}
|
||||
.v-top > * {vertical-align: top; display: inline-block;}
|
||||
.role-template-card p {margin: 0;}
|
||||
#roleTemplate {overflow: hidden;}
|
||||
#roleTemplate .btn-link:focus {background: unset;}
|
||||
#roleListContainer {height: 100%; overflow-y: scroll;}
|
||||
</style>
|
||||
<?php include 'promptdesignprogressbar.html.php';?>
|
||||
<div id='mainContent' class='main-content' style='height: calc(100vh - 120px); padding: 0;'>
|
||||
<form id="mainForm" onsubmit="return validateForm();" class='load-indicator main-form form-ajax' method='post' style='height: 100%;'>
|
||||
<div class='center-wrapper'>
|
||||
<div class='center-content' style="width: 100%; display: flex; flex-direction: row;">
|
||||
<div style="flex-grow: 1; padding: 20px;">
|
||||
<div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<h4><?php echo $lang->ai->prompts->assignRole;?></h4>
|
||||
<?php echo html::commonButton("<span>{$lang->ai->prompts->roleTemplate}</span> " . "<icon class='icon icon-first-page'></icon> ", 'id="expandRoleTemplatePanel"', 'btn btn-info');?>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->model;?></span></div>
|
||||
<div class='input mw-400px'>
|
||||
<?php echo html::select('model', $lang->ai->models->typeList, current(array_keys($lang->ai->models->typeList)), "class='form-control chosen' required");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->role;?></span></div>
|
||||
<div class='input mw-400px'><?php echo html::input('role', $prompt->role, "class='form-control' placeholder='{$lang->ai->prompts->rolePlaceholder}'");?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->characterization;?></span></div>
|
||||
<div class='input'><?php echo html::textarea('characterization', $prompt->characterization, "class='form-control' rows='4' placeholder='{$lang->ai->prompts->charPlaceholder}'");?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->roleTemplateSave;?></span></div>
|
||||
<div class='input' style="display: flex; align-items: center;"><?php echo html::radio('saveTemplate', $lang->ai->prompts->roleTemplateSaveList, 'discard');?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style='display: flex; flex-grow: 1; flex-direction: column-reverse;'>
|
||||
<div style='display: flex; justify-content: center;'><?php echo html::submitButton($lang->ai->nextStep, 'disabled name="jumpToNext" value="1"');?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="roleTemplate" style="display: none; width: 370px; flex-grow: 0; padding: 20px 24px; border-left: 1px solid #E6EAF1; background-color: #FCFDFE; border-top-right-radius: 4px; border-bottom-right-radius: 4px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
|
||||
<h4 class="v-top"">
|
||||
<?php echo "<span style='margin-right: 4px;'>{$lang->ai->prompts->roleTemplate}</span>" . " <i class='icon icon-help' data-toggle='tooltip' data-placement='top' title='{$lang->ai->prompts->roleTemplateTip}'></i>";?>
|
||||
</h4>
|
||||
<?php echo html::commonButton("<i class='icon icon-plus icon-sm text-primary'></i>", 'data-toggle="modal" data-target="#createRoleTemplateModal"', 'btn btn-link'); ?>
|
||||
</div>
|
||||
<div id="roleListContainer">
|
||||
<?php include './roletemplates.html.php';?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="createRoleTemplateModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only"><?php echo $lang->close; ?></span></button>
|
||||
<h4 class="modal-title"><?php echo $lang->ai->prompts->addRoleTemplate; ?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="createRoleForm" class="not-watch">
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->role;?></span></div>
|
||||
<div class='input mw-400px'><?php echo html::input('role', '', "class='form-control' placeholder='{$lang->ai->prompts->rolePlaceholder}'");?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->characterization;?></span></div>
|
||||
<div class='input'><?php echo html::textarea('characterization', '', "class='form-control' rows='4' placeholder='{$lang->ai->prompts->charPlaceholder}'");?></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="createRoleButton" type="button" class="btn btn-primary" data-dismiss="modal"><?php echo $lang->save; ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="editRoleTemplateModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only"><?php echo $lang->close; ?></span></button>
|
||||
<h4 class="modal-title"><?php echo $lang->ai->prompts->editRoleTemplate; ?> <i class='icon icon-help'></i> <span class="text-gray"><?php echo $lang->ai->prompts->editRoleTemplateTip;?></span></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editRoleForm" class="not-watch">
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->role;?></span></div>
|
||||
<div class='input mw-400px'><?php echo html::input('role', '', "class='form-control' placeholder='{$lang->ai->prompts->rolePlaceholder}'");?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->characterization;?></span></div>
|
||||
<div class='input'><?php echo html::textarea('characterization','', "class='form-control' rows='4' placeholder='{$lang->ai->prompts->charPlaceholder}'");?></div>
|
||||
</div>
|
||||
<input type="hidden" name="id">
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="editRoleButton" type="button" class="btn btn-primary" data-dismiss="modal"><?php echo $lang->save; ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function validateForm()
|
||||
{
|
||||
let pass = true;
|
||||
const model = document.getElementById('model')?.value;
|
||||
if(!model)
|
||||
{
|
||||
$.zui.messager.danger('<?php echo sprintf($lang->ai->validate->noEmpty, $lang->ai->prompts->model);?>');
|
||||
pass = false;
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
|
||||
(function ()
|
||||
{
|
||||
let roleId = null;
|
||||
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
$('select[name="model"]').change(function()
|
||||
{
|
||||
var model = $(this).val();
|
||||
if (model) $('button[type="submit"]').removeAttr('disabled');
|
||||
if (!model) $('button[type="submit"]').attr('disabled', 'disabled');
|
||||
});
|
||||
$('select[name="model"]').trigger('change');
|
||||
});
|
||||
|
||||
$('#createRoleButton').on('click', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
const formData = new FormData(document.getElementById('createRoleForm'));
|
||||
if(!formData.get('role'))
|
||||
{
|
||||
$.zui.messager.danger('<?php echo sprintf($lang->ai->validate->noEmpty, $lang->ai->prompts->role);?>');
|
||||
return false;
|
||||
}
|
||||
$.ajax({
|
||||
url: createLink('ai', 'roleTemplates'),
|
||||
type: 'POST',
|
||||
data: {method: 'create', role: formData.get('role'), characterization: formData.get('characterization')},
|
||||
dataType: 'html',
|
||||
success: function(response)
|
||||
{
|
||||
$('#createRoleForm [name="role"], #createRoleForm [name="characterization"]').each(function() {$(this).val('');});
|
||||
$.zui.messager.success('<?php echo $lang->ai->prompts->roleAddedSuccess; ?>');
|
||||
$('#roleList').html($($.parseHTML(response)).filter('#roleList').html());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#editRoleButton').on('click', function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
const formData = new FormData(document.getElementById('editRoleForm'));
|
||||
if(!formData.get('role'))
|
||||
{
|
||||
$.zui.messager.danger('<?php echo sprintf($lang->ai->validate->noEmpty, $lang->ai->prompts->role);?>');
|
||||
return false;
|
||||
}
|
||||
$.ajax({
|
||||
url: createLink('ai', 'roleTemplates'),
|
||||
type: 'POST',
|
||||
data: {
|
||||
method: 'edit',
|
||||
id: formData.get('id'),
|
||||
role: formData.get('role'),
|
||||
characterization: formData.get('characterization')
|
||||
},
|
||||
dataType: 'html',
|
||||
success: function(response)
|
||||
{
|
||||
$('#editRoleForm [name="role"], #editRoleForm [name="characterization"]').each(function() {$(this).val('');});
|
||||
$.zui.messager.success('<?php echo $lang->ai->prompts->roleAddedSuccess; ?>');
|
||||
$('#roleList').html($($.parseHTML(response)).filter('#roleList').html());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#roleListContainer').on('click', function(e)
|
||||
{
|
||||
const button = e.target.closest('#roleListContainer button');
|
||||
if(!button) return;
|
||||
const card = button.closest('.role-template-card');
|
||||
if(!card) return;
|
||||
e.preventDefault();
|
||||
|
||||
const id = card.dataset.id;
|
||||
|
||||
switch (button.dataset.action)
|
||||
{
|
||||
case 'apply':
|
||||
{
|
||||
$('#mainForm input[name="role"]').val(card.querySelector('.role').innerText).toggleClass('focus', true);
|
||||
$('#mainForm textarea[name="characterization"]').val(card.querySelector('.characterization').innerText).toggleClass('focus', true);
|
||||
setTimeout(() => {
|
||||
$('#mainForm input[name="role"]').toggleClass('focus', false);
|
||||
$('#mainForm textarea[name="characterization"]').toggleClass('focus', false);
|
||||
}, 1000);
|
||||
roleId = id;
|
||||
break;
|
||||
}
|
||||
case 'edit':
|
||||
{
|
||||
const model = $('#editRoleTemplateModal');
|
||||
model.find('input[name="id"]').val(id);
|
||||
model.find('input[name="role"]').val(card.querySelector('.role').innerText);
|
||||
model.find('textarea[name="characterization"]').val(card.querySelector('.characterization').innerText);
|
||||
model.modal('toggle');
|
||||
break;
|
||||
}
|
||||
case 'del':
|
||||
{
|
||||
if (window.confirm('<?php echo $lang->ai->prompts->roleDelConfirm; ?>')) {
|
||||
$.ajax({
|
||||
url: createLink('ai', 'roleTemplates'),
|
||||
type: 'POST',
|
||||
data: {method: 'delete', id: id},
|
||||
dataType: 'html',
|
||||
success: function (response) {
|
||||
$.zui.messager.success('<?php echo $lang->ai->prompts->roleDelSuccess; ?>');
|
||||
$('#roleList').html($($.parseHTML(response)).filter('#roleList').html());
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#mainForm').on('submit', function()
|
||||
{
|
||||
if($('#mainForm input[name="saveTemplate"]:checked').val() === 'discard') return true;
|
||||
if((roleId && !$(`#role-template-${roleId}`).length) || ($('#mainForm input[name="role"]').val() === $(`role-${roleId}`).text() && $('#mainForm textarea[name="characterization"]').val() === $(`characterization-${roleId}`).text()))
|
||||
{
|
||||
$('#mainForm input[name="saveTemplate"]#saveTemplatediscard').prop('checked', true);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const expandRoleTemplatePanel = document.getElementById('expandRoleTemplatePanel');
|
||||
if(expandRoleTemplatePanel)
|
||||
{
|
||||
expandRoleTemplatePanel.addEventListener('click', function (e) {
|
||||
const roleTemplate = document.getElementById('roleTemplate');
|
||||
const isPanelExpanded = roleTemplate.style.display === 'block';
|
||||
expandRoleTemplatePanel.querySelector('icon').className = isPanelExpanded ? 'icon icon-first-page' : 'icon icon-last-page';
|
||||
if (roleTemplate) {
|
||||
roleTemplate.style.display = isPanelExpanded ? 'none' : 'block';
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -1,145 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The design step bar view file of AI module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Jianyu Chen <chenjianyu@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
|
||||
<?php include '../../common/view/header.lite.html.php'; ?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<form method="post" class="main-form form-ajax">
|
||||
<div class='center-block'>
|
||||
<div class="main-header">
|
||||
<p>
|
||||
<?php echo $this->lang->ai->audit->designPrompt; ?>
|
||||
<strong><?php echo $prompt->name ?></strong>
|
||||
<span class='label label-id'> <?php echo $prompt->id; ?></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="bg-gray-3" style="display: flex;">
|
||||
<div style="flex-basis: 50%; flex-grow: 1;padding: 5px 20px 5px 10px; border-right: #E6EAF1 1px solid">
|
||||
<h4><?php echo $this->lang->ai->prompts->assignRole; ?></h4>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $this->lang->ai->prompts->role; ?></span></div>
|
||||
<div
|
||||
class='input'><?php echo html::input('role', $prompt->role, "class='form-control' placeholder='{$this->lang->ai->prompts->rolePlaceholder}'"); ?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $this->lang->ai->prompts->characterization; ?></span></div>
|
||||
<div
|
||||
class='input'><?php echo html::textarea('characterization', $prompt->characterization, "class='form-control' rows='4' placeholder='{$this->lang->ai->prompts->charPlaceholder}'"); ?></div>
|
||||
</div>
|
||||
<h4><?php echo $this->lang->ai->prompts->selectDataSource; ?></h4>
|
||||
<div class='content-row'>
|
||||
<div class='input-label text-gray'><span><?php echo $this->lang->ai->prompts->object; ?></span></div>
|
||||
<div class='input'
|
||||
style="text-align: left; padding: 6px 0;"><?php echo $this->lang->ai->dataSource[$prompt->module]['common']; ?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label text-gray'><span><?php echo $this->lang->ai->prompts->field; ?></span></div>
|
||||
<div class='input' style="padding: 6px 0;">
|
||||
<?php
|
||||
$sources = explode(',', $prompt->source);
|
||||
$sources = array_filter($sources);
|
||||
end($sources);
|
||||
$lastKey = key($sources);
|
||||
foreach($sources as $key => $source)
|
||||
{
|
||||
$isLastElem = ($key === $lastKey);
|
||||
list($object, $field) = explode('.', $source);
|
||||
echo $this->lang->ai->dataSource[$prompt->module][$object][$field] . ($isLastElem ? '' : $this->lang->separater);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<h4><?php echo $this->lang->ai->prompts->setPurpose; ?></h4>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->purpose; ?></span></div>
|
||||
<div
|
||||
class='input'><?php echo html::textarea('purpose', $prompt->purpose, "class='form-control' rows='6' placeholder='{$lang->ai->prompts->purposeTip}' required"); ?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->elaboration; ?></span></div>
|
||||
<div
|
||||
class='input'><?php echo html::textarea('elaboration', $prompt->elaboration, "class='form-control' rows='6' placeholder='{$lang->ai->prompts->elaborationTip}'"); ?></div>
|
||||
</div>
|
||||
<h4><?php echo $this->lang->ai->prompts->setTargetForm; ?></h4>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $this->lang->ai->prompts->selectTargetForm; ?></span></div>
|
||||
<div class='input' style="padding: 6px 0;">
|
||||
<?php
|
||||
$targetForm = explode('.', $prompt->targetForm);
|
||||
echo $this->lang->ai->targetForm[$targetForm[0]][$targetForm[1]];
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex-basis: 50%; flex-grow: 1; display: flex; flex-direction: column; word-break: break-all;">
|
||||
<div style="padding: 5px 10px; border-bottom: #E6EAF1 1px solid">
|
||||
<h4
|
||||
style="margin-bottom: 24px;"><?php echo sprintf($this->lang->ai->models->promptFor, $this->lang->ai->models->typeList['openai-gpt35']); ?></h4>
|
||||
<p class="text-gray"><?php echo $this->lang->ai->prompts->assignRole; ?></p>
|
||||
<p id="roleDisplay"><?php echo $prompt->role; ?></p>
|
||||
<p id="characterizationDisplay"><?php echo $prompt->characterization; ?></p>
|
||||
</div>
|
||||
<div style="padding: 5px 10px; border-bottom: #E6EAF1 1px solid">
|
||||
<p class="text-gray"><?php echo $this->lang->ai->prompts->selectDataSource; ?></p>
|
||||
<p><?php echo htmlspecialchars($dataPrompt); ?></p>
|
||||
</div>
|
||||
<div style="padding: 5px 10px;">
|
||||
<p class="text-gray"><?php echo $this->lang->ai->prompts->setPurpose; ?></p>
|
||||
<p id="purposeDisplay"><?php echo $prompt->purpose; ?></p>
|
||||
<p id="elaborationDisplay"><?php echo $prompt->elaboration; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 15px; padding-left: 10px;">
|
||||
<p style="display: inline-block"><?php echo $this->lang->ai->audit->afterSave; ?></p>
|
||||
<?php echo html::radio('backLocation', $this->lang->ai->audit->backLocationList, 1); ?>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: center; margin-top: 10px;">
|
||||
<?php echo html::submitButton($this->lang->save, '', 'btn btn-primary'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
(function()
|
||||
{
|
||||
const submitButton = document.getElementById('submit');
|
||||
if(!submitButton) return;
|
||||
const purpose = document.getElementsByName('purpose')[0];
|
||||
if(!purpose) return;
|
||||
|
||||
if(!purpose.value)
|
||||
{
|
||||
submitButton.disabled = true;
|
||||
}
|
||||
purpose.addEventListener('input', function()
|
||||
{
|
||||
submitButton.disabled = !purpose.value;
|
||||
});
|
||||
})();
|
||||
|
||||
function reloadPrompt(promptId, objectId)
|
||||
{
|
||||
parent.$.zui.closeModal();
|
||||
|
||||
$('body', window.parent.document).attr('data-loading', '<?php echo $lang->ai->execute->loading;?>');
|
||||
$('body', window.parent.document).addClass('load-indicator loading');
|
||||
|
||||
let link = createLink('ai', 'promptexecute', 'promptId=' + promptId + '&objectId=' + objectId);
|
||||
link = link.replace('onlybody=yes', '');
|
||||
const aTag = document.createElement('a');
|
||||
aTag.href = link;
|
||||
aTag.style.display = 'none';
|
||||
parent.document.body.appendChild(aTag);
|
||||
aTag.click();
|
||||
}
|
||||
</script>
|
||||
<?php include '../../common/view/footer.lite.html.php'; ?>
|
||||
@@ -1,159 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The design step bar view file of AI module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Jianyu Chen <chenjianyu@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<header id="mainMenu" class='design-steps'>
|
||||
<?php echo html::a(inlink("prompts"), html::commonButton("<i class='icon icon-angle-left'></i> $lang->goback", 'style="font-weight: bold;"', 'btn btn-link'));?>
|
||||
<div class='steps'>
|
||||
<?php
|
||||
$step = preg_replace('/^prompt/', '', $app->methodName);
|
||||
$stepSequence = array('assignrole', 'selectdatasource', 'setpurpose', 'settargetform', 'finalize');
|
||||
|
||||
$currentStepIndex = array_search($step, $stepSequence);
|
||||
$lastActiveStepIndex = array_search($lastActiveStep, $stepSequence);
|
||||
|
||||
$stepstatus = array();
|
||||
|
||||
foreach($stepSequence as $index => $stepName)
|
||||
{
|
||||
if($index < $currentStepIndex)
|
||||
{
|
||||
$stepstatus[$stepName] = 'active';
|
||||
}
|
||||
elseif($index > $currentStepIndex && $index <= $lastActiveStepIndex + 1)
|
||||
{
|
||||
$stepstatus[$stepName] = 'clickable';
|
||||
}
|
||||
else
|
||||
{
|
||||
$stepstatus[$stepName] = 'disabled';
|
||||
}
|
||||
|
||||
if($index == $currentStepIndex)
|
||||
{
|
||||
$stepstatus[$stepName] = 'current';
|
||||
}
|
||||
}
|
||||
|
||||
foreach($lang->ai->designStepNav as $stepKey => $stepLang)
|
||||
{
|
||||
$arrow = '';
|
||||
$currentStepStatus = current($stepstatus);
|
||||
$nextStepStatus = next($stepstatus);
|
||||
if($stepKey != end($stepSequence))
|
||||
{
|
||||
$arrowClass = $currentStepStatus == $nextStepStatus ||($currentStepStatus == 'clickable' && $nextStepStatus == 'disabled') ? 'outline-arrow' : 'solid-arrow';
|
||||
$arrow = "<div class='$arrowClass'></div>";
|
||||
}
|
||||
$aTag = html::a(inlink("prompt$stepKey", "prompt=$prompt->id"), $stepLang);
|
||||
echo "<div class='step $currentStepStatus'>$aTag$arrow</div>";
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<button id="saveButton" type="submit" class="btn btn-primary visibility-hidden" form="mainForm"><i class="icon icon-save icon-sm"></i> <?php echo $lang->save ?></button>
|
||||
<div class="modal fade" id="returnConfirmModal">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<p><?php echo sprintf($lang->ai->validate->dirtyForm, $lang->ai->designStepNav[$step])?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="footer">
|
||||
<div>
|
||||
<?php echo html::a(inlink("prompts"), html::commonButton("<i class='icon icon-back icon-sm'></i> $lang->goback", '', 'btn btn-info'));?>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo $lang->cancel?></button>
|
||||
<button type="button" class="btn btn-primary"><?php echo $lang->save?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
let isPromptDesignDirty = false;
|
||||
|
||||
(function()
|
||||
{
|
||||
const steps = document.getElementsByClassName('steps')[0];
|
||||
if(steps)
|
||||
{
|
||||
for(let step of steps.children)
|
||||
{
|
||||
step.addEventListener('mouseenter', function()
|
||||
{
|
||||
if(step.lastElementChild?.classList.contains('outline-arrow'))
|
||||
{
|
||||
step.lastElementChild.classList.remove('outline-arrow');
|
||||
step.lastElementChild.classList.add('hover-arrow');
|
||||
}
|
||||
|
||||
if(step.previousElementSibling?.lastElementChild?.classList.contains('outline-arrow'))
|
||||
{
|
||||
step.previousElementSibling.lastElementChild.classList.add('solid-arrow');
|
||||
}
|
||||
});
|
||||
step.addEventListener('mouseleave', function()
|
||||
{
|
||||
if(step.lastElementChild?.classList.contains('hover-arrow'))
|
||||
{
|
||||
step.lastElementChild.classList.remove('hover-arrow');
|
||||
step.lastElementChild.classList.add('outline-arrow');
|
||||
}
|
||||
|
||||
if(step.previousElementSibling?.lastElementChild?.classList.contains('outline-arrow') && step.previousElementSibling?.lastElementChild?.classList.contains('solid-arrow'))
|
||||
{
|
||||
step.previousElementSibling.lastElementChild.classList.remove('solid-arrow');
|
||||
}
|
||||
});
|
||||
|
||||
const link = step.querySelector('a');
|
||||
if(!link) continue;
|
||||
link.addEventListener('click', function(e)
|
||||
{
|
||||
if(!isPromptDesignDirty) return;
|
||||
const result = validateForm();
|
||||
if(!result) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
const submitButton = document.getElementById('saveButton');
|
||||
if(!submitButton) return;
|
||||
submitButton.click();
|
||||
})
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
(function()
|
||||
{
|
||||
const backButton = document.querySelector('.design-steps button:first-child');
|
||||
if(!backButton) return;
|
||||
backButton.addEventListener('click', function(e)
|
||||
{
|
||||
if(!isPromptDesignDirty) return;
|
||||
$('#returnConfirmModal').modal('show', 'fit');
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
const modalSaveButton = document.querySelector('#returnConfirmModal .btn-primary');
|
||||
if(!modalSaveButton) return;
|
||||
modalSaveButton.addEventListener('click', function()
|
||||
{
|
||||
if(validateForm() === false) return;
|
||||
const submitButton = document.getElementById('saveButton');
|
||||
if(!submitButton) return;
|
||||
submitButton.click();
|
||||
location.href = createLink('ai', 'prompts');
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</header>
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The ai prompt edit view file of ai module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wenrui LI <liwenrui@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::set('requiredFields', $config->ai->createprompt->requiredFields);?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $this->lang->ai->prompts->edit . " $lang->colon " . $prompt->name;?></h2>
|
||||
</div>
|
||||
<form method="post" class="main-form form-ajax" target="hiddenwin">
|
||||
<table class="table table-form">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="w-80px"><?php echo $this->lang->ai->prompts->name;?></th>
|
||||
<td><?php echo html::input('name', $prompt->name, "class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="w-80px"><?php echo $this->lang->ai->prompts->description;?></th>
|
||||
<td><?php echo html::textarea('desc', $prompt->desc, "rows='6' class='form-control'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="text-center form-actions">
|
||||
<?php echo html::submitButton($lang->save, '', 'btn btn-wide btn-primary');?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(function() {
|
||||
$('input[name="name"]').on('input', function()
|
||||
{
|
||||
if($(this).val().length > 0)
|
||||
{
|
||||
$('button[type="submit"]').removeClass('disabled').removeAttr('disabled');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('button[type="submit"]').addClass('disabled').attr('disabled', 'disabled');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The ai prompt finalize view file of ai module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wenrui LI <liwenrui@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
|
||||
<style>
|
||||
.center-wrapper {display: flex; justify-content: center; height: 100%;}
|
||||
.center-content {width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center;}
|
||||
#info-form {display: flex; flex-direction: column; min-width: 800px;}
|
||||
.content-row {display: flex; flex-direction: row; padding: 8px 0px;}
|
||||
.input-label {width: 120px; padding: 6px 12px; text-align: right;}
|
||||
.input {flex-grow: 1;}
|
||||
.input-tip {padding: 6px 12px;}
|
||||
</style>
|
||||
|
||||
<?php include 'promptdesignprogressbar.html.php';?>
|
||||
<div id='mainContent' class='main-content' style='height: calc(100vh - 120px);'>
|
||||
<form id="mainForm" onsubmit="return validateForm();" class='load-indicator main-form form-ajax' method='post' style='height: 100%;'>
|
||||
<div class='center-wrapper'>
|
||||
<div class='center-content'>
|
||||
<div id='info-form'>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->prompt->name;?></span></div>
|
||||
<div class='input mw-600px'><?php echo html::input('name', $prompt->name, "class='form-control' required");?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->prompt->module;?></span></div>
|
||||
<div class='input mw-200px'><?php echo html::input('module', $lang->ai->prompts->modules[$prompt->module], "class='form-control' disabled");?></div>
|
||||
<div class='input-tip text-gray'><?php echo $lang->ai->moduleDisableTip;?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->prompt->desc;?></span></div>
|
||||
<div class='input mw-600px'><?php echo html::textarea('desc', $prompt->desc, "rows='6' class='form-control'");?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style='display: flex; flex-grow: 1; flex-direction: column-reverse;'>
|
||||
<div style='display: flex; justify-content: center;'><?php echo html::submitButton($lang->ai->prompts->action->publish, 'disabled name="jumpToNext" value="1"');?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function validateForm()
|
||||
{
|
||||
let pass = true;
|
||||
const name = document.getElementById('name')?.value;
|
||||
if(!name)
|
||||
{
|
||||
$.zui.messager.danger('<?php echo sprintf($lang->ai->validate->noEmpty, $lang->ai->prompts->name);?>');
|
||||
pass = false;
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
$(function() {
|
||||
$('input[name="name"]').on('input', function()
|
||||
{
|
||||
if($(this).val().length > 0)
|
||||
{
|
||||
$('#submit').removeAttr('disabled');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#submit').attr('disabled', 'disabled');
|
||||
}
|
||||
});
|
||||
$('input[name="name"]').trigger('input');
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -1,492 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The ai prompt data source selection view file of ai module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wenrui LI <liwenrui@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
|
||||
<?php js::set('dataSource', $dataSource);?>
|
||||
<?php js::set('dataSourceLang', $lang->ai->dataSource);?>
|
||||
|
||||
<style>
|
||||
.center-wrapper {display: flex; justify-content: center; height: 100%;}
|
||||
.center-content {width: 100%; height: 100%; display: flex; flex-direction: column;}
|
||||
#data-selector {display: flex; flex-direction: row; height: 100%; margin-bottom: 16px; max-height: calc(100% - 48px);}
|
||||
#data-sources {flex-grow: 2; display: flex; flex-direction: row; margin-right: 16px;}
|
||||
#data-selected {flex-grow: 1; display: flex; flex-direction: column;}
|
||||
.heading > * {display: inline-block; padding: 4px 0;}
|
||||
#data-category-select {flex-grow: 1; background-color: #f8f8f8; border: 1px solid #eee; border-right: none;}
|
||||
#data-category-select > ul {padding: 16px; margin: 0; list-style: none;}
|
||||
#data-category-select > ul > li > a.active {font-weight: bold;}
|
||||
#data-categories {flex-grow: 1; display: flex; flex-direction: column;}
|
||||
#data-properties {flex-grow: 3; display: flex; flex-direction: column; height: 100%;}
|
||||
#data-properties > .heading {padding: 4px 20px;}
|
||||
#data-properties > .heading > h4 {margin: 6px 0;}
|
||||
#data-property-select {flex-grow: 1; border: 1px solid #eee; border-left: none; height: calc(100% - 44px); overflow-y: auto;}
|
||||
#data-property-selector {height: 100%; width: 100%;}
|
||||
#data-selected-items {flex-grow: 1; border: 1px solid #eee; height: calc(100% - 44px); overflow-y: auto; scrollbar-gutter: stable;}
|
||||
.obj-view {display: flex; flex-direction: column; padding: 20px;}
|
||||
.obj-view:not(:first-of-type) {border-top: 1px solid #eee;}
|
||||
.obj-view-body {display: grid; padding: 4px 20px; grid-template-columns: repeat(4, 1fr);}
|
||||
.obj-view-header.checkbox-inline, .obj-view-item.checkbox-inline {margin: 4px; cursor: unset;}
|
||||
.obj-view-item.checkbox-inline+.obj-view-item.checkbox-inline {margin-left: 4px; margin-top: 4px;}
|
||||
.checkbox-inline > label, .checkbox-inline > input {cursor: pointer;}
|
||||
.checkbox-primary > label {padding-left: 0;}
|
||||
#selected-data-sorter .list-group {padding: 0; margin: 0; list-style: none; overflow: hidden;}
|
||||
#selected-data-sorter .list-group-item {padding: 8px 16px; display: flex; align-items: center; cursor: move; transition: background-color 0.2s ease-in-out;}
|
||||
#selected-data-sorter .list-group-item > span {flex-grow: 1;}
|
||||
#selected-data-sorter .list-group-item:hover {background-color: #eef5ff;}
|
||||
#selected-data-sorter .list-group-item .drag-icon {padding-right: 8px; opacity: 0; transition: opacity 0.2s ease-in-out;}
|
||||
#selected-data-sorter .list-group-item:hover .drag-icon {opacity: 1;}
|
||||
#selected-data-sorter .list-group-item::before {content: counter(list-item); counter-increment: list-item; display: inline-block; width: 2ch; padding-right: 28px;}
|
||||
#selected-data-sorter .list-group-item.drag-shadow::before {content: '';}
|
||||
#selected-data-sorter .list-group-item .remove-icon {cursor: pointer; padding: 2px;}
|
||||
|
||||
@media (max-width: 1366px)
|
||||
{
|
||||
.obj-view-body {grid-template-columns: repeat(3, 1fr);}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
/* Store and sync value of datasource input, change by checkbox changes. */
|
||||
class DataSourceStore
|
||||
{
|
||||
value = [];
|
||||
listeners = [];
|
||||
|
||||
/* Get store value. */
|
||||
get value()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/* Set store value. */
|
||||
set value(value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/* Reset store value. */
|
||||
reset()
|
||||
{
|
||||
this.value = [];
|
||||
|
||||
/* Notify listeners. */
|
||||
this.listeners.forEach(l => (l(this.value)));
|
||||
}
|
||||
|
||||
/* Sync value from form checkboxes. */
|
||||
sync()
|
||||
{
|
||||
const dataSources = document.querySelectorAll('#data-property-selector');
|
||||
const value = this.value;
|
||||
dataSources.forEach(dataSource =>
|
||||
{
|
||||
const group = dataSource.getAttribute('object-group');
|
||||
const items = dataSource.querySelectorAll('input[type="checkbox"]');
|
||||
items.forEach(item =>
|
||||
{
|
||||
const itemPropName = item.getAttribute('prop');
|
||||
if(itemPropName.includes('.'))
|
||||
{
|
||||
if(item.checked)
|
||||
{
|
||||
if(!value.includes(itemPropName)) value.push(itemPropName);
|
||||
}
|
||||
else if(value.includes(itemPropName)) value.splice(value.indexOf(itemPropName), 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
this.value = value;
|
||||
document.querySelector('#datasource').value = value.join(',');
|
||||
|
||||
/* Notify listeners. */
|
||||
this.listeners.forEach(l => (l(this.value)));
|
||||
}
|
||||
|
||||
/* Subscribe for store value changes. */
|
||||
subscribe(listener)
|
||||
{
|
||||
this.listeners.push(listener);
|
||||
}
|
||||
|
||||
/* Unsubscribe for store value changes. */
|
||||
unsubscribe(listener)
|
||||
{
|
||||
this.listeners = this.listeners.filter(l => l !== listener);
|
||||
}
|
||||
}
|
||||
window.dataSourceStore = new DataSourceStore(); // Create store instance.
|
||||
|
||||
/* Data property selector component, declared as custom element. */
|
||||
class DataPropertySelector extends HTMLDivElement
|
||||
{
|
||||
/* Render with given options. */
|
||||
render(options)
|
||||
{
|
||||
this.innerHTML = '';
|
||||
|
||||
/* Get options. */
|
||||
const {group} = options;
|
||||
|
||||
/* Get data source. */
|
||||
const dataSource = window.dataSource[group];
|
||||
const dataSourceLang = window.dataSourceLang[group];
|
||||
|
||||
/* Render data source. */
|
||||
for(const [source, props] of Object.entries(dataSource))
|
||||
{
|
||||
const objView = document.createElement('div');
|
||||
objView.classList.add('obj-view');
|
||||
|
||||
const headerItem = new DataPropertyCheckbox();
|
||||
headerItem.classList.add('obj-view-header');
|
||||
headerItem.setAttribute('source', source);
|
||||
headerItem.setAttribute('prop', group);
|
||||
objView.appendChild(headerItem);
|
||||
|
||||
const objViewBody = document.createElement('div');
|
||||
objViewBody.classList.add('obj-view-body');
|
||||
props.forEach(prop =>
|
||||
{
|
||||
const item = new DataPropertyCheckbox();
|
||||
item.classList.add('obj-view-item');
|
||||
item.setAttribute('source', source);
|
||||
item.setAttribute('group', group);
|
||||
item.setAttribute('prop', prop);
|
||||
objViewBody.appendChild(item);
|
||||
});
|
||||
objView.appendChild(objViewBody);
|
||||
|
||||
this.appendChild(objView);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle attr change, rerender. */
|
||||
attributeChangedCallback(name, oldValue, newValue)
|
||||
{
|
||||
if(name === 'object-group' && oldValue !== newValue) this.render({group: newValue});
|
||||
}
|
||||
|
||||
/* Define observed attr. */
|
||||
static get observedAttributes()
|
||||
{
|
||||
return ['object-group'];
|
||||
}
|
||||
}
|
||||
customElements.define('data-property-selector', DataPropertySelector, {extends: 'div'});
|
||||
|
||||
/*
|
||||
* Checkbox with label for data selection, declared as custom element.
|
||||
*
|
||||
* @prop {string} group - Data source group name (selected from left sidebar).
|
||||
* @prop {string} source - Data source category (sub-group).
|
||||
* @prop {string} prop - Data source property name.
|
||||
*/
|
||||
class DataPropertyCheckbox extends HTMLDivElement
|
||||
{
|
||||
/* Render checkbox with label, listen for events. */
|
||||
render()
|
||||
{
|
||||
this.innerHTML = '';
|
||||
|
||||
const prop = this.getAttribute('prop');
|
||||
const source = this.getAttribute('source');
|
||||
const group = this.getAttribute('group');
|
||||
|
||||
this.classList.add('checkbox-primary', 'checkbox-inline');
|
||||
const itemOption = document.createElement('input');
|
||||
itemOption.setAttribute('type', 'checkbox');
|
||||
itemOption.setAttribute('prop', !!group ? `${source}.${prop}` : source);
|
||||
this.appendChild(itemOption);
|
||||
const itemLabel = document.createElement('label');
|
||||
itemLabel.appendChild(document.createTextNode(!!group ? dataSourceLang[group][source][prop] : dataSourceLang[prop][source].common));
|
||||
|
||||
/* Setup event listeners. */
|
||||
itemLabel.addEventListener('click', (e =>
|
||||
{
|
||||
itemOption.checked = !itemOption.checked;
|
||||
this.handleCheck(itemOption.checked);
|
||||
}).bind(this));
|
||||
itemOption.addEventListener('change', (e =>
|
||||
{
|
||||
this.handleCheck(itemOption.checked);
|
||||
}).bind(this));
|
||||
|
||||
this.appendChild(itemLabel);
|
||||
}
|
||||
|
||||
/* Handle check all for checkbox group, bidirectionally. And push selections into datasource input. */
|
||||
handleCheck(newValue)
|
||||
{
|
||||
if(this.classList.contains('obj-view-header'))
|
||||
{
|
||||
const objViewBody = this.parentElement.querySelector('.obj-view-body');
|
||||
for(const item of objViewBody.querySelectorAll('.obj-view-item input[type="checkbox"]')) item.checked = newValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
const objViewBody = this.parentElement;
|
||||
const headerItem = objViewBody.parentElement.querySelector('.obj-view-header input[type="checkbox"]');
|
||||
const groupItems = objViewBody.querySelectorAll('.obj-view-item input[type="checkbox"]');
|
||||
let allChecked = true;
|
||||
for(const item of groupItems)
|
||||
{
|
||||
if(!item.checked) allChecked = false;
|
||||
}
|
||||
headerItem.checked = allChecked;
|
||||
}
|
||||
window.dataSourceStore.sync();
|
||||
}
|
||||
|
||||
/* Handle attr change, rerender. */
|
||||
attributeChangedCallback()
|
||||
{
|
||||
/* Skip rendering if props not complete. */
|
||||
if(!this.hasAttribute('prop') || !this.hasAttribute('source')) return;
|
||||
this.render();
|
||||
}
|
||||
|
||||
/* Define observed attr. */
|
||||
static get observedAttributes()
|
||||
{
|
||||
return ['group', 'source', 'prop'];
|
||||
}
|
||||
}
|
||||
customElements.define('data-property-checkbox', DataPropertyCheckbox, {extends: 'div'});
|
||||
|
||||
/* Selected data column title, dynamically render with current group and selection. */
|
||||
class SelectedTitleText extends HTMLSpanElement
|
||||
{
|
||||
/* Setup re-render trigger. */
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
window.dataSourceStore.subscribe(this.render.bind(this));
|
||||
}
|
||||
|
||||
/* Render span from string format. */
|
||||
render()
|
||||
{
|
||||
this.innerHTML = '';
|
||||
|
||||
const format = this.getAttribute('format');
|
||||
const group = this.getAttribute('group');
|
||||
const count = window.dataSourceStore.value.length;
|
||||
|
||||
const args = [dataSourceLang[group].common, count];
|
||||
this.innerHTML = format.replace(/{(\d+)}/g, ((match, argIndex) =>
|
||||
{
|
||||
return typeof args[argIndex] !== 'undefined' ? args[argIndex] : match;
|
||||
}));
|
||||
}
|
||||
|
||||
/* Handle attr change, rerender. */
|
||||
attributeChangedCallback(name, oldValue, newValue)
|
||||
{
|
||||
if(name === 'group' && oldValue !== newValue) this.render();
|
||||
}
|
||||
|
||||
/* Define observed attr. */
|
||||
static get observedAttributes()
|
||||
{
|
||||
return ['group'];
|
||||
}
|
||||
}
|
||||
customElements.define('selected-title-text', SelectedTitleText, {extends: 'span'});
|
||||
|
||||
/* Sortable selected data column list, dynamically render with current selection. */
|
||||
class SelectedDataSorter extends HTMLDivElement
|
||||
{
|
||||
/* Setup re-render trigger. */
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
window.dataSourceStore.subscribe(this.render.bind(this));
|
||||
}
|
||||
|
||||
/* Render sortable list from current selection. */
|
||||
render()
|
||||
{
|
||||
this.innerHTML = '';
|
||||
|
||||
const group = this.getAttribute('group');
|
||||
const props = window.dataSourceStore.value;
|
||||
|
||||
const listView = document.createElement('ol');
|
||||
listView.classList.add('list-group');
|
||||
props.forEach(prop =>
|
||||
{
|
||||
const item = document.createElement('li');
|
||||
item.classList.add('list-group-item');
|
||||
item.setAttribute('prop', prop);
|
||||
|
||||
const dragIcon = document.createElement('i');
|
||||
dragIcon.classList.add('icon', 'icon-move', 'text-gray', 'drag-icon');
|
||||
item.appendChild(dragIcon);
|
||||
|
||||
const [source, propName] = prop.split('.');
|
||||
const itemText = document.createElement('span');
|
||||
itemText.appendChild(document.createTextNode(`${dataSourceLang[group][source].common} / ${dataSourceLang[group][source][propName]}`));
|
||||
item.appendChild(itemText);
|
||||
|
||||
const itemRemove = document.createElement('i');
|
||||
itemRemove.classList.add('icon', 'icon-close', 'text-gray', 'remove-icon');
|
||||
itemRemove.addEventListener('click', (() =>
|
||||
{
|
||||
window.dataSourceStore.value = window.dataSourceStore.value.filter(p => p !== prop);
|
||||
document.querySelector(`.obj-view-item input[type="checkbox"][prop="${prop}"]`).click();
|
||||
}).bind(this));
|
||||
item.appendChild(itemRemove);
|
||||
|
||||
listView.appendChild(item);
|
||||
});
|
||||
this.appendChild(listView);
|
||||
|
||||
/* Setup sortable on this list. */
|
||||
$(listView).sortable(
|
||||
{
|
||||
handle: '.list-group-item',
|
||||
finish: () =>
|
||||
{
|
||||
const props = [];
|
||||
for(const item of listView.querySelectorAll('.list-group-item')) props.push(item.getAttribute('prop'));
|
||||
window.dataSourceStore.value = props;
|
||||
window.dataSourceStore.sync();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Handle attr change, rerender. */
|
||||
attributeChangedCallback(name, oldValue, newValue)
|
||||
{
|
||||
if(name === 'group' && oldValue !== newValue) this.render();
|
||||
}
|
||||
|
||||
/* Define observed attr. */
|
||||
static get observedAttributes()
|
||||
{
|
||||
return ['group'];
|
||||
}
|
||||
}
|
||||
customElements.define('selected-data-sorter', SelectedDataSorter, {extends: 'div'});
|
||||
</script>
|
||||
|
||||
<?php include 'promptdesignprogressbar.html.php';?>
|
||||
<div id='mainContent' class='main-content' style='height: calc(100vh - 120px);'>
|
||||
<form id="mainForm" onsubmit="return validateForm();" class='load-indicator main-form form-ajax' method='post' style='height: 100%;'>
|
||||
<div class='center-wrapper'>
|
||||
<div class='center-content'>
|
||||
<div id='data-selector'>
|
||||
<div id='data-sources'>
|
||||
<div id='data-categories'>
|
||||
<div class='heading text-center'>
|
||||
<h4><?php echo $lang->ai->prompts->selectDataSource;?></h4>
|
||||
</div>
|
||||
<div id='data-category-select'>
|
||||
<ul>
|
||||
<?php foreach(array_keys($dataSource) as $index => $objectGroupKey):?>
|
||||
<li data-group-key='<?php echo $objectGroupKey;?>'>
|
||||
<a class='btn btn-block <?php echo $objectGroupKey == $activeDataSource ? ' active btn-info' : ' btn-link';?>' <?php echo $objectGroupKey == $activeDataSource ? 'style="background-color: #E6F0FF;"' : '';?>>
|
||||
<?php echo $lang->ai->dataSource[$objectGroupKey]['common'];?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach;?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id='data-properties'>
|
||||
<div class='heading'>
|
||||
<h4><?php echo $lang->ai->prompts->selectData;?></h4>
|
||||
<small class='text-gray'><?php echo $lang->ai->prompts->selectDataTip;?></small>
|
||||
</div>
|
||||
<div id='data-property-select'>
|
||||
<div id='data-property-selector' is='data-property-selector' object-group='<?php echo $activeDataSource;?>'></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='data-selected'>
|
||||
<div class='heading'>
|
||||
<h4><span id='selected-title-text' is='selected-title-text' group='<?php echo $activeDataSource;?>' format='<?php echo $lang->ai->prompts->selectedFormat;?>'></span></h4>
|
||||
</div>
|
||||
<div id='data-selected-items'>
|
||||
<div id='selected-data-sorter' is='selected-data-sorter' group='<?php echo $activeDataSource;?>'></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style='display: flex; flex-grow: 1; flex-direction: column-reverse;'>
|
||||
<?php echo html::hidden('datasource', $prompt->source);?>
|
||||
<?php echo html::hidden('datagroup', $activeDataSource);?>
|
||||
<div style='display: flex; justify-content: center;'><?php echo html::submitButton($lang->ai->nextStep, 'disabled name="jumpToNext" value="1"');?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
function validateForm()
|
||||
{
|
||||
let pass = true;
|
||||
const dataGroup = document.querySelector('input[name="datagroup"]')?.value;
|
||||
const dataSource = document.querySelector('input[name="datasource"]')?.value;
|
||||
if(!dataGroup || !dataSource)
|
||||
{
|
||||
$.zui.messager.danger('<?php echo sprintf($lang->ai->validate->noEmpty, $lang->ai->prompts->selectDataSource);?>');
|
||||
pass = false;
|
||||
}
|
||||
if(pass)
|
||||
{
|
||||
/* Disable checkboxes to prevent them getting posted as form data. */
|
||||
$('#data-property-selector input[type="checkbox"]').each(function() {$(this).attr('disabled', 'disabled');});
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
$(function()
|
||||
{
|
||||
/* Handle category switching. */
|
||||
$('#data-category-select > ul > li > a').click(function()
|
||||
{
|
||||
if($(this).hasClass('active')) return;
|
||||
|
||||
/* Reset selected data. */
|
||||
window.dataSourceStore.reset();
|
||||
|
||||
/* Update menu states. */
|
||||
$('#data-category-select > ul > li > a').removeClass('active btn-info').addClass('btn-link');
|
||||
$(this).addClass('active btn-info').removeClass('btn-link');
|
||||
|
||||
var currentGroup = $(this).parent().attr('data-group-key');
|
||||
|
||||
/* Update other component props. */
|
||||
$('#data-property-selector').attr('object-group', currentGroup);
|
||||
$('#selected-title-text').attr('group', currentGroup);
|
||||
$('#selected-data-sorter').attr('group', currentGroup);
|
||||
|
||||
/* Update hidden form fields. */
|
||||
$('input[name="datagroup"]').val(currentGroup);
|
||||
});
|
||||
|
||||
/* Toggle disabled submit button. */
|
||||
window.dataSourceStore.subscribe(function(value)
|
||||
{
|
||||
$('#submit').attr('disabled', !value.length);
|
||||
});
|
||||
|
||||
<?php if($prompt->source):?>
|
||||
/* Init checkboxes states. */
|
||||
'<?php echo $prompt->source;?>'.split(',').filter(function(p) {return p;}).forEach(function(prop)
|
||||
{
|
||||
$('#data-property-selector input[type="checkbox"][prop="' + prop + '"]').click();
|
||||
});
|
||||
<?php endif;?>
|
||||
});
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -1,167 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The ai prompt set purpose view file of ai module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wenrui LI <liwenrui@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
|
||||
<style>
|
||||
.center-wrapper {display: flex; justify-content: center; height: 100%;}
|
||||
.center-content {width: 100%; height: 100%; display: flex; flex-direction: column;}
|
||||
#purpose-setter {display: flex; flex-direction: row; max-height: calc(100% - 32px);}
|
||||
#purpose-setter > div {flex-grow: 1; flex-basis: 0; padding: 0px 12px;}
|
||||
.content-wrapper {padding: 0 12px; overflow-x: hidden; overflow-y: auto; scrollbar-gutter: stable;}
|
||||
.content-row {display: flex; flex-direction: row; padding: 8px 0px;}
|
||||
.input-label {width: 120px; padding: 6px 12px; text-align: right;}
|
||||
.input {flex-grow: 1;}
|
||||
#prompt-preview-wrapper {margin: 16px 0; height: calc(100% - 48px);}
|
||||
#prompt-preview {padding: 8px; border: 1px solid #E6EAF1; border-radius: 4px; background-color: #f8f8f8; min-height: 100px; height: 100%; overflow-y: auto;}
|
||||
#prompt-preview {cursor: default; user-select: none;}
|
||||
#prompt-preview .active {background-color: #d6e5fe;}
|
||||
#prompt-preview .prompt-data, #prompt-preview .prompt-role, #prompt-preview .prompt-text {border-bottom: 1px solid #E6EAF1; padding: 16px 0;}
|
||||
#prompt-preview .prompt-data {padding-top: 0;}
|
||||
#prompt-preview .prompt-text {border-bottom: unset; padding-bottom: 0;}
|
||||
#prompt-preview .block-header {padding-bottom: 8px;}
|
||||
#prompt-preview .block-content > div + div {margin-top: 4px;}
|
||||
#prompt-preview .prompt-text-part + .prompt-text-part {margin-top: 4px;}
|
||||
#prompt-previewer {font-weight: bold;}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
class PromptPreviewer extends HTMLDivElement
|
||||
{
|
||||
connectedCallback()
|
||||
{
|
||||
if(this.isConnected)
|
||||
{
|
||||
['purpose', 'elaboration'].forEach(id =>
|
||||
{
|
||||
['input', 'focus', 'blur'].forEach(event => document.getElementById(id).addEventListener(event, this.updatePromptView));
|
||||
});
|
||||
}
|
||||
this.render();
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
this.innerHTML = '';
|
||||
|
||||
/* Create textarea input preview. */
|
||||
['purpose', 'elaboration'].forEach(id =>
|
||||
{
|
||||
const contentView = document.createElement('div');
|
||||
contentView.id = `${id}-preview`;
|
||||
contentView.classList.add('prompt-text-part');
|
||||
contentView.innerHTML = document.getElementById(id).value;
|
||||
if(id === document.activeElement.id) contentView.classList.add('active');
|
||||
this.appendChild(contentView);
|
||||
});
|
||||
}
|
||||
|
||||
updatePromptView()
|
||||
{
|
||||
/* Sync textarea input preview. */
|
||||
['purpose', 'elaboration'].forEach(id =>
|
||||
{
|
||||
const contentView = document.getElementById(`${id}-preview`);
|
||||
contentView.innerHTML = document.getElementById(id).value;
|
||||
if(id === document.activeElement.id)
|
||||
{
|
||||
contentView.classList.add('active');
|
||||
}
|
||||
else
|
||||
{
|
||||
contentView.classList.remove('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define('prompt-previewer', PromptPreviewer, {extends: 'div'});
|
||||
</script>
|
||||
|
||||
<?php include 'promptdesignprogressbar.html.php';?>
|
||||
<div id='mainContent' class='main-content' style='height: calc(100vh - 120px);'>
|
||||
<form id="mainForm" onsubmit="return validateForm();" class='load-indicator main-form form-ajax' method='post' style='height: 100%;'>
|
||||
<div class='center-wrapper'>
|
||||
<div class='center-content'>
|
||||
<div id='purpose-setter'>
|
||||
<div id='purpose-input'>
|
||||
<h4><?php echo $lang->ai->prompts->purpose;?></h4>
|
||||
<div class='content-wrapper'>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->purpose;?></span></div>
|
||||
<div class='input'><?php echo html::textarea('purpose', $prompt->purpose, "class='form-control' rows='6' placeholder='{$lang->ai->prompts->purposeTip}' required");?></div>
|
||||
</div>
|
||||
<div class='content-row'>
|
||||
<div class='input-label'><span><?php echo $lang->ai->prompts->elaboration;?></span></div>
|
||||
<div class='input'><?php echo html::textarea('elaboration', $prompt->elaboration, "class='form-control' rows='6' placeholder='{$lang->ai->prompts->elaborationTip}'");?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4><?php echo $lang->ai->prompts->inputPreview;?></h4>
|
||||
<div id='prompt-preview-wrapper'>
|
||||
<div id='prompt-preview'>
|
||||
<div class='prompt-data'>
|
||||
<div class='block-header text-gray'><?php echo $lang->ai->prompts->dataPreview;?></div>
|
||||
<div class='block-content code' style='white-space: pre-wrap; word-break: break-word;'><?php echo $dataPreview;?></div>
|
||||
</div>
|
||||
<div class='prompt-role'>
|
||||
<div class='block-header text-gray'><?php echo $lang->ai->prompts->rolePreview;?></div>
|
||||
<div class='block-content'>
|
||||
<div><?php echo $prompt->role;?></div>
|
||||
<div><?php echo $prompt->characterization;?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='prompt-text'>
|
||||
<div class='block-header text-gray'><?php echo $lang->ai->prompts->promptPreview;?></div>
|
||||
<div id='prompt-previewer' is='prompt-previewer'></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style='display: flex; flex-grow: 1; flex-direction: column-reverse;'>
|
||||
<div style='display: flex; justify-content: center;'><?php echo html::submitButton($lang->ai->nextStep, 'disabled name="jumpToNext" value="1"');?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function validateForm()
|
||||
{
|
||||
let pass = true;
|
||||
const purpose = document.getElementById('purpose')?.value;
|
||||
if(!purpose)
|
||||
{
|
||||
pass = false;
|
||||
$.zui.messager.danger('<?php echo sprintf($lang->ai->validate->noEmpty, $lang->ai->prompts->purpose);?>');
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
$(function()
|
||||
{
|
||||
$('#purpose').on('input', function()
|
||||
{
|
||||
const val = $(this).val();
|
||||
if(val.length > 0)
|
||||
{
|
||||
$('#submit').removeAttr('disabled');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#submit').attr('disabled', 'disabled');
|
||||
}
|
||||
});
|
||||
$('#purpose').trigger('input');
|
||||
});
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -1,192 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The ai prompt target form select view file of ai module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wenrui LI <liwenrui@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
|
||||
<style>
|
||||
.center-wrapper {display: flex; justify-content: center; height: 100%;}
|
||||
.center-content {width: 100%; height: 100%; display: flex; flex-direction: column;}
|
||||
#select-form {display: flex; flex-direction: row; max-height: calc(100% - 32px);}
|
||||
#select-form > div {flex-grow: 1; flex-basis: 0; padding: 0px 12px;}
|
||||
.content-row {display: flex; flex-direction: row; padding: 8px 0px;}
|
||||
.input-label {width: 120px; padding: 6px 12px; text-align: right;}
|
||||
.input {flex-grow: 1;}
|
||||
#prompt-preview-wrapper {margin: 16px 0; height: calc(100% - 48px);}
|
||||
#prompt-preview {padding: 8px; border: 1px solid #E6EAF1; border-radius: 4px; background-color: #f8f8f8; min-height: 100px; height: 100%; overflow-y: auto; cursor: default; user-select: none;}
|
||||
#prompt-preview .active {background-color: #d6e5fe;}
|
||||
#prompt-preview .prompt-data, #prompt-preview .prompt-role, #prompt-preview .prompt-text {border-bottom: 1px solid #E6EAF1; padding: 16px 0;}
|
||||
#prompt-preview .prompt-data {padding-top: 0;}
|
||||
#prompt-preview .prompt-text {border-bottom: unset; padding-bottom: 0;}
|
||||
#prompt-preview .block-header {padding-bottom: 8px;}
|
||||
#prompt-preview .block-content > div + div {margin-top: 4px;}
|
||||
#prompt-preview .prompt-text-part + .prompt-text-part {margin-top: 4px;}
|
||||
#prompt-previewer {font-weight: bold;}
|
||||
#form-selector .header > * {display: inline-block;}
|
||||
#form-selector .content {margin: 6px 0; max-height: calc(100% - 47px); overflow-y: auto; border: 1px solid #E6EAF1; border-left: none;}
|
||||
.target-form-group {display: grid; grid-template-columns: 120px 1fr; grid-gap: 8px; border: 1px solid #E6EAF1; border-right: 0;}
|
||||
.target-form-group:first-of-type {border-top: none;}
|
||||
.target-form-group:last-of-type {border-bottom: none;}
|
||||
.target-form-group + .target-form-group {border-top: unset;}
|
||||
.target-form-group .header {display: flex; align-items: center; padding: 0 12px; background-color: #f8f8f8;}
|
||||
.target-form-group .options {display: grid; padding: 12px 16px; grid-template-columns: repeat(4, 1fr);}
|
||||
.target-form-group .option {padding: 4px 0;}
|
||||
.target-form-group .option label {cursor: pointer;}
|
||||
.target-form-group .option input {cursor: pointer;}
|
||||
#go-test-btn {margin-left: 16px;}
|
||||
|
||||
@media (max-width: 1366px)
|
||||
{
|
||||
.target-form-group .options {grid-template-columns: repeat(3, 1fr);}
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php include 'promptdesignprogressbar.html.php';?>
|
||||
<div id='mainContent' class='main-content' style='height: calc(100vh - 120px);'>
|
||||
<form id="mainForm" onsubmit="return validateForm();" class='load-indicator main-form form-ajax' method='post' style='height: 100%;'>
|
||||
<div class='center-wrapper'>
|
||||
<div class='center-content'>
|
||||
<div id='select-form'>
|
||||
<div id='form-selector'>
|
||||
<div class='header'>
|
||||
<h4><?php echo $lang->ai->prompts->selectTargetForm;?></h4>
|
||||
<small class='text-gray'><?php echo $lang->ai->prompts->selectTargetFormTip;?></small>
|
||||
</div>
|
||||
<div class='content'>
|
||||
<?php foreach ($config->ai->targetForm as $name => $forms):?>
|
||||
<div class='target-form-group'>
|
||||
<div class='header text-gray'>
|
||||
<div><?php echo $lang->ai->targetForm[$name]['common'];?></div>
|
||||
</div>
|
||||
<div class='options'>
|
||||
<?php foreach(array_keys($forms) as $form):?>
|
||||
<div class='option'>
|
||||
<input type='radio' name='targetForm' value='<?php echo "$name.$form";?>' <?php echo "$name.$form" == $prompt->targetForm ? 'checked' : '';?>>
|
||||
<label><?php echo $lang->ai->targetForm[$name][$form];?></label>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4><?php echo $lang->ai->prompts->inputPreview;?></h4>
|
||||
<div id='prompt-preview-wrapper'>
|
||||
<div id='prompt-preview'>
|
||||
<div class='prompt-data'>
|
||||
<div class='block-header text-gray'><?php echo $lang->ai->prompts->dataPreview;?></div>
|
||||
<div class='block-content code' style='white-space: pre-wrap; word-break: break-word;'><?php echo $dataPreview;?></div>
|
||||
</div>
|
||||
<div class='prompt-role'>
|
||||
<div class='block-header text-gray'><?php echo $lang->ai->prompts->rolePreview;?></div>
|
||||
<div class='block-content'>
|
||||
<div><?php echo $prompt->role;?></div>
|
||||
<div><?php echo $prompt->characterization;?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='prompt-text'>
|
||||
<div class='block-header text-gray'><?php echo $lang->ai->prompts->promptPreview;?></div>
|
||||
<div class='block-content'>
|
||||
<div><?php echo $prompt->purpose;?></div>
|
||||
<div><?php echo $prompt->elaboration;?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style='display: flex; flex-grow: 1; flex-direction: column-reverse;'>
|
||||
<div style='display: flex; justify-content: center;'>
|
||||
<?php echo html::submitButton($lang->ai->nextStep, 'disabled name="jumpToNext" value="1"');?>
|
||||
<button type='submit' name='goTesting' value='1' id='go-test-btn' disabled class='btn btn-wide btn-secondary'><?php echo $lang->ai->goTesting;?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function validateForm()
|
||||
{
|
||||
let pass = false;
|
||||
const radios = document.getElementsByName('targetForm');
|
||||
for(let radio of radios)
|
||||
{
|
||||
if(radio.checked)
|
||||
{
|
||||
pass = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!pass)
|
||||
{
|
||||
$.zui.messager.danger('<?php echo sprintf($lang->ai->validate->noEmpty, $lang->ai->prompts->selectTargetForm);?>');
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
$(function()
|
||||
{
|
||||
$('.target-form-group .option label').click(function()
|
||||
{
|
||||
$(this).parent().find('input').click();
|
||||
});
|
||||
|
||||
$('.target-form-group .option input').change(function()
|
||||
{
|
||||
var $selected = $('.target-form-group').find('.option input:checked');
|
||||
if($selected.length > 0)
|
||||
{
|
||||
$('#submit').removeAttr('disabled');
|
||||
$('#go-test-btn').removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
$('.target-form-group .option input:checked').trigger('change');
|
||||
|
||||
/* Enable buttons after going testing. */
|
||||
$('#mainForm').ajaxForm({
|
||||
success: function(response, status)
|
||||
{
|
||||
var message = response.msg;
|
||||
var location = response.locate;
|
||||
var target = response.target ? response.target : '#submit';
|
||||
if(message)
|
||||
{
|
||||
var $targetSubmitBtn = $(target);
|
||||
if($targetSubmitBtn.length)
|
||||
{
|
||||
$targetSubmitBtn.popover({
|
||||
container: 'body',
|
||||
trigger: 'manual',
|
||||
content: message,
|
||||
tipClass: 'popover-in-modal popover-success popover-form-result',
|
||||
placement: 'right',
|
||||
}).popover('show');
|
||||
setTimeout(function() {$targetSubmitBtn.popover('destroy');}, 2000);
|
||||
}
|
||||
}
|
||||
},
|
||||
finish: function(response, _, $form)
|
||||
{
|
||||
if(response.locate) setTimeout(function()
|
||||
{
|
||||
var $a = $('<a href="' + response.locate + '" target="_self"></a>');
|
||||
$a.appendTo('body');
|
||||
if($a.length) $a[0].click();
|
||||
$a.remove();
|
||||
}, 1200);
|
||||
$form.enableForm();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* The role template list component file of AI module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Jianyu Chen <chenjianyu@easycorp.ltd>
|
||||
* @package ai
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<div id="roleList" style="display: flex; flex-direction: column; gap:8px;">
|
||||
<?php foreach($roleTemplates as $role):?>
|
||||
<div id="role-template-<?php echo $role->id;?>" data-id="<?php echo $role->id;?>" class="role-template-card" style="border: 1px solid #D8DBDE; border-radius: 4px; padding: 12px; width: 100%;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; gap: 16px;">
|
||||
<p id="role-<?php echo $role->id;?>" class="role" style="overflow: hidden; white-space: nowrap; text-overflow: clip;" title="<?php echo $role->role; ?>"><?php echo $role->role; ?></p>
|
||||
<div style="display: flex; gap: 2px;">
|
||||
<?php echo html::commonButton("<span class='text-primary'>{$lang->app->common}</span>", "data-action='apply'", 'btn btn-link'); ?>
|
||||
<?php echo html::commonButton("<i class='icon icon-edit icon-sm text-primary'></i>", "data-action='edit'", 'btn btn-link'); ?>
|
||||
<?php echo html::commonButton("<i class='icon icon-trash icon-sm text-primary'></i>", "data-action='del'", 'btn btn-link'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<p id="characterization-<?php echo $role->id;?>" class="characterization text-gray" style="overflow: hidden; white-space: nowrap; text-overflow: clip; padding: 4px 0;" title="<?php echo $role->characterization;?>"><?php echo $role->characterization; ?></p>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
Reference in New Issue
Block a user