Давайте качественно проанализируем предыдущую статью ("Создание простого справочника"). В этой статье мы решили вопросы ведения реестра компьютеров. Но полностью? Понятно, что ПК имеет гораздо больше характеристик, чем мы предвидели. Это и список комплектующих, и подключены к нему периферийные устройства. Комплектующие тоже отличаются своими параметрами.
Очевидно, все эти данные нужно регистрировать в системе.
Для того, чтобы дополнить наш справочник, нам необходимо создать список этих комплектующих. По сути, он уже существует в справочнике номенклатуры. Однако в уже существующих данных необходимо добавить технические характеристики каждого комплектующего. Для этого, нам нужно создать такой справочник аналитики, который бы содержал список комплектующих (взятых из справочника номенклатуры) разбитых на группы и технические характеристики, записанных отдельным списком.
Для реализации этого мы создадим новый тип справочника аналитики.
Созданный на основе этого типа справочник аналитики будет содержать список комплектующих в одной таблице, а их характеристик - в другой.
Отображать на экране мы будем с помощью двух списков. В одном комплектующие, а во втором характеристики, причем при перемещении по списку комплектующих их характеристики будут изменяться автоматически.
Начнем ...
Немножко теории о создании типов справочников аналитики.Типы справочников аналитики сохраняются в папке Scripts / Cls. Для каждого типа создается отдельная папка. Ее название и будет обозначением нового типа. В этой папке могут быть следующие файлы:
-
class.xml - здесь описываются переменные справочника аналитики;
-
dpmapping.xml - здесь эти переменные привязываются к полям таблицы;
-
form.xml - описывается форма для добавления данных в справочник;
-
*. Js - обработчик событий на форме;
-
list.xml - описываются отображения списка;
-
list.js - описываются обработчик событий списка (не обязательно).
Если справочник по строкам, то в эту же папку надо поместить файл *. xml с описанием этого Grid `а и отдельную папку, в которой будут содержаться файлы для обработки данных в этом списке:
-
class.xml - здесь описываются переменные справочника аналитики;
dpmapping.xml - здесь эти переменные привязываются к полям таблицы;
form.xml - описывается форма для добавления данных в справочник;
-
*. Js - обработчик событий на форме.
Все просто и понятно. Достаточно внимательно описать переменные и поля, создать справочник аналитики нужного (созданного) типа и смело пользоваться.
Создания таблиц. Как создавать таблицы в существующей базе данных мы знаем. Поэтому здесь я просто приведу названия таблиц и списки полей.
Нам нужна одна таблица, где мы опишем код, название и серийный номер детали. Назовем ее CL_KOMPL. Поля, входят: FKOD, FNAME, FSERNOM.
Во второй нам нужно всего два поля (потом поймем почему так. Эту таблицу назовем CL_KOMPL_ROW. Поля, входят: FPARNAME, FPARZNACH.
Таблицы созданы и к этому больше не будем обращаться. Просто привожу в листинге 1 текст файла для их создания.
Листинг 1
<?xml version="1.0" encoding="UTF-8"?>
<STRU>
<TABLES>
<table attr="" dospath="cdbf" path="cl_mdb" pattern="CL_KOMPL" sys="com" table="CL_KOMPL"></table>
<table attr="" dospath="cdbf" path="cl_mdb" pattern="CL_KOMPL_ROW" sys="com" table="CL_KOMPL_ROW"></table>
</TABLES>
<PATTERNS>
<CL_KOMPL>
<PARENTS>
<PARENT pattern="FWIDPARENT"/>
</PARENTS>
<FIELDS>
<FWID_CL attr=" " type="long"/>
<FKOD attr=" " type="text"/>
<FNAME attr=" " type="text"/>
<FSERNOM attr=" " type="text"/>
<FREM attr=" " type="longtext"/>
</FIELDS>
</CL_KOMPL>
<CL_KOMPL_ROW>
<PARENTS>
<PARENT pattern="FWIDPARENT"/>
</PARENTS>
<FIELDS>
<FWID_CL attr=" " type="long"/>
<FPARNAME attr=" " type="long"/>
<FPARZNACH attr=" " type="text"/>
</FIELDS>
</CL_KOMPL_ROW>
</PATTERNS>
</STRU>
Для создания нового типа справочника выполним следующие действия:
1.В Scripts / Cls создадим папку с именем справочника (например, clkompl.
2.Создадим все необходимые файлы в папке.
Описание типа справочника (class.xml).Итак, поля таблиц созданы, можно описывать класс справочника. Напоминаю, что в классе мы описываем переменные справочника. Имена этим переменным мы будем давать такие, как и имена полей, заменяя первую букву F на H.
Листинг 2
<?xml version="1.0" encoding="UTF-8"?>
<DpCL type="clkompl" name="Комплектуючі|Комплектующие" sys="COM">
<Parents>
<parent classid="cls.CL1"/>
</Parents>
<Header>
<var name="HKOD" datatype="text"/>
<var name="HNAME" datatype="text"/>
<var name="HSERNOM" datatype="text"/>
<var name="HREM" datatype="text"/>
</Header>
<rows>
<row id="KLROWS" classid="KLROWS"/>
</rows>
</DpCL>
В листинге 2 не сложно разобраться самостоятельно. Здесь описано текст файла class.xml. Все же дадим некоторые пояснения.
<Header> - Описывает основные переменные справочника. Здесь указывается и тип этой переменной.
<rows> - привязывает к основному классу строки. Classid - идентификатор класса строк. Папку с таким же названием нужно создать в папке Scripts / Cls / название справочника.
Связь переменных с полями таблицы (dpmapping.xml). Теперь "привяжем" сменные справочника к полям таблицы. В системе "Дебет Плюс" это осуществляется с помощью файла dpmapping.xml, описанный в листинге 3.
Листинг 3
<?xml version="1.0" encoding="UTF-8"?>
<DpCL type="clkompl">
<Header>
<Tables>
<table name="CL" />
<table name="CLRELCLCL" ID="FWID_CL" />
<table name="CL_KOMPL" ID="FWID_CL" />
</Tables>
<Fields>
<field name="FWID" table="CL" var="ID" />
<field name="FTXT" table="CL" var="HTXT" />
<field name="FTXTS" table="CL" var="HTXTS" />
<field name="FCOD" table="CLRELCLCL" var="HCOD" />
<field name="FCL" table="CLRELCLCL" var="HCL" />
<field name="FWID_CL" table="CLRELCLCL" var="ID" />
<field name="FWID" table="CL_KOMPL" var="ID" />
<field name="FKOD" table="CL_KOMPL" var="HKOD" />
<field name="FNAME" table="CL_KOMPL" var="HNAME" />
<field name="FSERNOM" table="CL_KOMPL" var="HSERNOM" />
<field name="FREM" table="CL_KOMPL" var="HREM" />
</Fields>
</Header>
<Rows>
<Tables>
<table name="CL_KOMPL_ROW" reffield="FWID_CL"/>
</Tables>
</Rows>
</DpCL>
Здесь name - имя поля, table - имя таблицы, в которой это поле находится, var - имя переменной. Если все понятно - идем дальше.
<Файл list.xml. Как описывать отображения таблицы на экране мы уже знаем. Поэтому просто привожу листинг этого файла:
Листинг 4
<?xml version="1.0" encoding="UTF-8"?>
<list>
<grid>
<field field="kompl.FKOD" text="Код|Код" width="20" />
<field field="kompl.FNAME" text="Назва|Название" width="40" />
<field field="kompl.FSERNOM" text="Серійний номер|Серийный номер" width="20" />
<field field="kompl.FREM" text="Примітка|Примечание" width="70" />
</grid>
</list>
В этом коде kompl.FKOD означает <псевдоним таблицы> <название поля>. Такая комбинация образовалась в результате использования функции tie. Эта функция присоединяет к основной таблице другую по выбранным полям. Она используется в файле list.js
Файл list.js.
Листинг 5
function clAfterLoad()
{
this.addTies = clAddTies;
}
function clAddTies()
{
this.extTie("CL",Fcl);
this.extTieEx("ext0","fwid","CL","0");
this.subTie("CL_KOMPL", "kompl", "FWID_CL", "Fwid");
}
Функция clAfterLoad () обязательна. В ней описываются методы и свойства таблицы, отображаемой на гриде.
Попробуем объяснить только последнюю строку функции clAddTies (). Здесь:
-
"CL_KOMPL" - имя таблицы, присоединяется.
-
"Kompl" - псевдоним этой таблицы.
-
"FWID_CL", "Fwid" - поля таблиц, по которым эти таблицы объединяются.
Все довольно просто. Если вы создали и этот файл, то можем идти дальше.
Теперь нужно создать форму для заполнения таблицы. Опять же мы это уже с вами делали. Я остановлюсь только на использовании грида.
Файл form.js и form.xml.
Листинг 6
<?xml version="1.0" encoding="utf-8"?>
<Form>
<Controls col="3">
<Label text="№" width="80" gridwidth="1"/>
<TextField ID="FKOD" width="80" gridwidth="2"/>
<Label text="Назва:|Название:" gridwidth="1"/>
<TextField ID="FNAME" width="450" gridwidth="2"/>
<Label text="Серійний номер:|Серийный номер:" gridwidth="1"/>
<TextField ID="FSERNOM" width="450" gridwidth="2"/>
<Label text="Примітка:|Примечание:" gridwidth="1"/>
<TextField ID="FREM" width="450" gridwidth="2"/>
<grid ID="grid" width="700" height="250" gridwidth="3" align="fill" valign1="fill"/>
</Controls>
<script languige="JavaScript" src="form.js"/>
</Form>
Листинг 7
include("objects//DpCl.js");
include("gridedit.js");
var sDir = rootDirectory() + "cls/clkompl/";
var sTmpTbl = "TMP_KOMPL_ROW";
var sRowTbl = "CL_KOMPL_ROW";
var sRowClass = "KLROWS";
var objCl = extPar.dpObj;
var ctrlLinker;
var gridTbl;
var oGridEdit;
function onLoad()
{
this.onEscape = exit;
Caption(ru("Комплектующие", "Комплектуючі") +": "+ modeName(this.sMode));
ctrlLinker = new DpCtrlLinker(objCl);
FKOD.setMask("######");
FKOD.setFocus();
ctrlLinker.addLink("HKOD", FKOD);
ctrlLinker.addLink("HNAME", FNAME);
ctrlLinker.addLink("HSERNOM", FSERNOM);
ctrlLinker.addLink("HREM", FREM);
ctrlLinker.toControls();
loadGrid(this.sMode);
}
function loadGrid(sMode)
{
DropTable(sTmpTbl);
var sSQL = "SELECT * "
+ " INTO " + sTmpTbl
+ " FROM ^"+ sRowTbl;
var sWhere = " WHERE 1<>1 ";
if (sMode != "ADD")
sWhere = " WHERE FWID_CL="+ sqlTo(objCl.getID());
sSQL += sWhere;
ExecuteSQL(sSQL);
gridTbl = OpenTable("m", "SELECT * FROM "+ sTmpTbl);
clTie(gridTbl,"kk","="+250+",FPARNAME");
//browse(gridTbl);
grid.setXMLDir(sDir);
grid.setXMLFile("l_kompllist.xml");
grid.setTable(gridTbl);
grid.build();
grid.setData(sRowClass);
this.gridMenuInit = gridMenuInit;
this.gridMenuRum = gridMenuRum;
grid.loadMenuHandler(this,"gridMenuInit");
grid.selectMenuHandler(this,"gridMenuRum");
oGridEdit = new DpGridEdit(grid);
oGridEdit.canEdit = canEditRecord;
oGridEdit.saveRecord = saveRecord;
}
function saveRecord()
{
var rowID = parseInt(grid.getTable().getValue("fwid"));
var oRow = objCl.getRow(sRowClass, rowID);
if (oRow == null)
{
oRow = objCl.createRow(sRowClass);
oRow.setID(rowID);
objCl.appendRow(sRowClass, oRow);
}
with (oRow)
{
setVar("RPARNAME", gridTbl.getValue("FPARNAME"));
setVar("RPARZNACH", gridTbl.getValue("FPARZNACH"));
}
return true;
}
function canEditRecord()
{
return true;
}
function gridMenuInit(grid)
{
grid.AddMenuItem("ADD","Додати|Добавить");
if (!grid.getTable().isEmpty())
{
grid.AddMenuItem("EDIT","Редагувати|Редактировать");
grid.AddMenuItem("COPY","Копіювати|Копировать");
grid.AddMenuItem("DEL","Видалити|Удалить");
}
}
function gridMenuRum(sID, grid)
{
var tbl = grid.getTable();
var tName = tbl.getTableName();
var rowID = tbl.getValue("FWID");
switch(sID)
{
case "DEL":
var nGridPos = grid.getRowSelected();
ExecuteSQL("delete From "+ tName
+" where Fwid="+ sqlTo(rowID));
objCl.deleteRow(sRowClass, rowID);
tbl.requery();
tbl.setAbsolute(nGridPos-1);
grid.refresh();
break;
case "ADD": case "EDIT": case "COPY":
var oRow;
if(sID == "ADD")
oRow = objCl.createRow(sRowClass);
else if(sID == "EDIT")
oRow = objCl.getRow(sRowClass, rowID);
else if(sID == "COPY")
oRow = objCl.copyRow(sRowClass, rowID);
if(!oRow)
break;
if (!rowEdit(sID, oRow))
break;
tbl.requery();
grid.refresh();
break;
}
return true;
}
function onSave()
{
ctrlLinker.toVars();
storeToDb(sRowTbl, sTmpTbl);
exit();
}
function rowEdit(sMode, oRow)
{
var par = new Object();
par.dpObj = oRow;
par.mode = sMode;
par.tblName = sTmpTbl;
par.dpObj.hasExt = hasExt;
par.formFile = "cls/"+ objCl.sClassId +"/KLROWS/form.xml";
showWindow(par.formFile, "XMLDLG", par);
if(par.escape)
return false;
var id = oRow.getID();
if(inList(sMode, "ADD", "COPY"))
objCl.appendRow(sRowClass, oRow);
obj2DB(id, oRow.jObj, null, sTmpTbl);
return true;
}
function hasExt()
{
return false;
}
function storeToDb(sTbl, tmpTbl)
{
var sFld = GetPatternIntersection (sTbl, sTbl);
ExecuteSQL("DELETE FROM ^"+ sTbl +" WHERE FWID_CL="+ sqlTo(objCl.getID()));
ExecuteSQL("UPDATE "+ tmpTbl +" SET Fwid_cl="+ sqlTo(objCl.getID()));
ExecuteSQL("INSERT INTO ^"+ sTbl +" ("+ sFld +")"
+" SELECT "+ sFld +" FROM "+ tmpTbl);
}
function exit()
{
gridTbl.close();
DropTable(sTmpTbl);
}
include("sys/DpBaseDlg.js");
Грид загружается на форму и инициализируется функцией loadGrid. Поля на форме привязываются к переменным класса с помощью объекта ctrlLinker. Это дает возможность удобного хранения данных и загрузки данных на форму. Все остальное - это обработка данных. Ищите описание объектов и функций в файлах бизнес-логики системы "Дебет Плюс".
Один момент. Описания грида, который находится на форме находится в файле l_kompllist.xml. Вот его листинга.
Листинг 8
<?xml version="1.0" encoding="UTF-8"?>
<grid>
<field field="=tcl('CL','TXT',250,FPARNAME)" text="Параметр|Параметр" width="20" />
<field field="FPARZNACH" text="Значення|Значение" width="30" />
</grid>
Для успешного выполнения кода необходимо создать справочник аналитики № 250 "Характеристики комплектующих.
Теперь создадим класс для добавления строк. Поскольку мы полностью разработали один класс, то нет проблемы разобраться как сделать другой.
В папке Scripts / Cls / название справочника создадим папку KLROWS. В ней четыре файла. Приводим без комментариев.
class.xml
<?xml version="1.0" encoding="utf-8"?>
<DpCl type="KLROWS">
<Header>
<var name="RWID_CL" datatype="long"/>
<var name="RPARNAME" datatype="text"/>
<var name="RPARZNACH" datatype="text"/>
</Header>
</DpCl>
dpmapping.xml
<?xml version="1.0" encoding="utf-8"?>
<DpCl type="KLROWS">
<Header>
<Tables>
<table name="CL_KOPML_ROWS"/>
</Tables>
<Fields>
<field name="FWID_CL" table="CL_KOMPL_ROWS" var="RWID_CL"/>
<field name="FPARNAME" table="CL_KOPML_ROWS" var="RPARNAME"/>
<field name="FPARZNACH" table="CL_KOPML_ROWS" var="RPARZNACH"/>
</Fields>
</Header>
</DpCl>
form.xml
<?xml version="1.0" encoding="utf-8" ?>
<Form>
<Controls col="4" >
<ComboBox ID="FPARNAME">
<option selected="true" value="-">---</option>
</ComboBox>
<Label text="Значення|Значение"/>
<TextField ID="FPARZNACH" width="130" colspan="2"/>
</Controls>
<script languige="JavaScript" src="form.js"/>
</Form>
form.js
include("Objects/DpVal.js");
include("Objects/DpBank.js");
var obj = extPar.dpObj;
var oVal;
var ctrlLinker;
function onLoad()
{
Caption(ru("Комплектующие", "Комплектуючі")
+ ": " + modeName(extPar.mode));
//Блок для заповнення списку ComboBox з довідника аналітики № 250
var tt = OpenTable("Select a.FCOD,b.FWID,b.FTXT, a.FWID_CL From ^CL b, ^CLRELCLCL a WHERE b.FWID=a.FWID_CL and a.FCL=250 ORDER BY b.FTXT");
for(tt.MoveFirst();!tt.IsEOF();tt.MoveNext())
{
var sVal = tt.getValue("FCOD");
var sTxt = tt.getValue("FTXT");
FPARNAME.addItem(sVal,sTxt);
}
FPARNAME.selectedIndex = obj.getVar("RPARNAME");
//showObject(obj);
//Конец блока
ctrlLinker = new DpCtrlLinker(obj);
ctrlLinker.addLink("RPARNAME", FPARNAME);
ctrlLinker.addLink("RPARZNACH", FPARZNACH);
ctrlLinker.updateData(false);
}
function onSave()
{
ctrlLinker.updateData(true);
}
function hasExt()
{
// return false;
}
include("sys\\DpBaseDlg.js");
Теперь добавим справочник аналитики созданного типа и вот, что у нас получилось: