如果一个系统已经设计开发成型,现在用户要求在这个系统上增加档案信息管理部分,主要功能包括归档、归档保管、信息检索查询、销毁以及审核等功能,该怎样设计和实现呢?
一般的做法是在更改原来的系统表结构,增加相关的档案系统的字段,然后再编程实现,这样的做法需要对原来系统进行比较大的改造,原系统或者档案信息系统的更改都会引起连锁反应,无疑这样做的工作量会很大。
经过思考,我的做法是不对原系统进行任何改动,只是单独增加有关档案信息的表,通过对归档的表的灵活处理来实现归档和查询,这样一来,很大程度上增加了系统的灵活性。
一、设计思路
⒈建立了一个档案目录表,在知道档案目录表下要归档的原数据表后,用数据窗口装载该表的记录,根据归档要求进行筛选,具体归档时,在档案列表里插入一条记录,对满足要求的记录进行打包,然后根据查询要求更新查询索引表(档案号码与相关查询字段的关系表),填写归档记录的相关属性,并把打包后的二进制文件更新至该记录。
⒉具体查询时,根据查询字段,提出具体的档案号码,进而提出具体的档案记录,然后把该二进制文件释放到本地硬盘,用数据窗口装载,根据查询要求定位到具体记录。
具体流程如下:
●需要着重考虑的问题:
⑴、如何避免重复归档?
因为归档记录已经打包,与原表无关了,我们的解决方法是:根据归档二进制文件对应的数据表名称以及相关主关键字段设置,把已经归档的记录从原表中删除(这里只是在归档显示时删除,对原表记录不做任何改动)。
⑵、如何存储归档的实际记录?
在PB里,数据窗口的数据可以另存为一种以PSR结尾的报表文件格式,程序里用读取该文件内容后在存入档案列表的Image字段,在还原数据记录时,只需要把Image字段还原为本地的PSR文件,并装载入数据窗口,那么存储的原数据就会显现出来。
二、数据表设计
⑴ 在档案系统里增加表来对原系统所用的表及字段进行登记,相当于在档案系统里把要归档表的情况做了个快照,在具体实现时的表名称依次是:DaTableAll(记录所要归档的表的英文名称和汉字名称)、DaTableFieldSet(记录归档原表的主关键字段设置),还有筛选表及字段设置表DaFilter_TableField,索引表及字段设置Dasy_Tablefiledset。
⑵ 档案计划表(DaJH)。
⑶ 建立档案目录表(Daml)以及具体目录下归档所对应的表(DaTableSet)。
⑷ 为了加快查询档案速度,必须建立依据具体查询所对应的检索记录表,比如为了在档案系统部分里依据人员姓名或者身份证号码快速查询到具体档案号码进而调出具体电子档案,需要建立人员姓名、身份证号码、档案号码这三个字段的索引记录表(DaIndex_Member),等等.
这一部分可依据查询要求进行相应表的建立,具体编程可以用动态游标来处理初始没有考虑而其后又增加的归档要求。
⑸ 建立档案记录列表(DaList),用于保存具体的归档记录。
三、程序实现界面
四、核心部分代码
//【选择所属归档目录】按钮的代码:
long LDAMLID,L1,LParent
string S3,S1,S2
//打开档案目录窗口,选择一个归档目录
open(w_select_da_gdml)
LDAMLID=long(message.stringparm)
if LDAMLID>0 then
//寻找它的上级目录
ddlb_1.reset()
//找到编码
select c10,c07 into :S1,:LParent from daml where c06=:LDAMLID using NowDB;
S2=S1
do while LParent<>-1
select c10,c07 into :S1,:LParent from daml where c06=:LParent using NowDB;
S2=S1+S2
loop
SDACODE=S2
sle_daml.text=S2
//提出所归档的数据表
declare c1 cursor for select c03,c04 from datableset where c01=:LDAMLID using NowDB;
open c1;
fetch c1 into :S1,:S2;
do while NowDB.sqlcode=0
//加入到要选择归档的电子表列表中
ddlb_1.additem(S2+fill(" ",200)+S1)
fetch c1 into :S1,:S2;
loop
close c1;
if not ddlb_1.totalitems()>0 then
cb_gd.enabled=false
else
cb_gd.enabled=true
end if
end if
//【提取数据】按钮的代码:
blob b_1
long LFOR,JFOR,KFOR,LFINDROW,LTEMP,LJSCOUNT
string S1,SFIND,STEMP,SField,SType,SPSP
datetime DT_TEMP
decimal DEC_TEMP
wf_setstatus("请稍候......正在提取数据")
tab_1.tabpage_1.dw_1.settransobject(NowDB)
tab_1.tabpage_1.dw_1.retrieve()
//检查已经归档数据
wf_setstatus("请稍候......正在检查归档数据,这可能需要比较长的时间!!!")
if tab_1.tabpage_2.dw_2.rowcount()>0 then
//提取检索字段
dw_datablefieldset.reset()
s1=gf_getoriginalsql(dw_datablefieldset)
S1=S1+" where c01='"+SCurrentTable_English+"'"
dw_datablefieldset.setsqlselect(S1)
dw_datablefieldset.retrieve()
wf_setstatus("请稍候......正在检查归档数据【"+string(tab_1.tabpage_2.dw_2.rowcount())+"】")
for LFOR=1 to tab_1.tabpage_2.dw_2.rowcount()
SPSP=tab_1.tabpage_2.dw_2.getitemstring(LFOR,"c25")
SPSP=left(SPSP,len(SPSP) - 4)
if SPSP=SDACODE then
//生成档案数据
S1=tab_1.tabpage_2.dw_2.getitemstring(LFOR,"c01")
selectblob c19 into :b_1 from dalist where c01=:S1 using NowDB;
wf_setstatus("请稍候......正在检查归档数据"+string(tab_1.tabpage_2.dw_2.rowcount())+"/"+string(string(LFOR)))
//将二进制文件解压至本地硬盘
if fileexists("c:\PSP.PSR") then
filedelete("c:\PSP.PSR")
end if
//写至内存
gf_write_mb("c:\PSP.PSR",b_1)
//装载至数据窗口
dw_PSP.reset()
dw_PSP.setredraw(false)
dw_PSP.dataobject="c:\PSP.PSR"
dw_PSP.setredraw(true)
//逐条记录检查
LJSCOUNT=dw_PSP.rowcount()
if LJSCOUNT>0 then
for JFOR=1 to LJSCOUNT
wf_setstatus("请稍候......正在检查归档数据"+string(LJSCOUNT)+"/"+string(string(JFOR)))
yield()
SFind=""
for KFOR=1 to dw_datablefieldset.rowcount()
yield()
SField=dw_datablefieldset.getitemstring(KFOR,"c02")
SType =dw_datablefieldset.getitemstring(KFOR,"c04")
//生成检索语句
STEMP=""
choose case upper(SType)
case "STRING"
STEMP=dw_psp.getitemstring(JFOR,SField)
STEMP=SField+"='"+STEMP+"'"
case "INTEGER"
LTEMP=dw_psp.getitemnumber(JFOR,SField)
STEMP=SField+"="+string(LTEMP)
case "DECIMAL"
DEC_TEMP=dw_psp.getitemdecimal(JFOR,SField)
STEMP=SField+"="+string(DEC_TEMP)
end choose
if SFind="" then
SFind=STEMP
else
SFind=SFind+" and "+STEMP
end if
next
LFINDROW=tab_1.tabpage_1.dw_1.find(SFind,1,tab_1.tabpage_1.dw_1.rowcount())
if LFINDROW>0 then tab_1.tabpage_1.dw_1.deleterow(LFINDROW)
next
end if
end if
next
end if
wf_setstatus("提取数据完毕!")
//【执行归档】按钮的代码:
boolean CanGD
string SFalse,S1,S2,S3,SDACODEPPP
long L1,L2,LMAX,LFOR,LDAJHID
string SDAMC,SDAJHMC,SDAMEMO,SGJC
long LVALUE
blob B_PSR
datetime DT_NOW,DT_NULL
setnull(DT_NULL)
CANGD=true
DT_NOW=gf_getservernowtime()
SDAMC=trim(sle_damc.text)
if SDAMC="" then
CanGD=false
SFalse="档案名称为空,不能归档案!"
end if
LDAJHID=long(left(sle_dajh.text,5))
SDAJHMC=trim( right(sle_dajh.text,len(sle_dajh.text) - 5) )
if trim(sle_dajh.text)="" then
CanGD=false
SFalse="档案计划名称为空,不能归档案!"
end if
if trim(sle_daml.text)="" then
CanGD=false
SFalse="选择的档案目录为空,不能归档案!"
end if
if not dw_1.rowcount()>0 then
CanGD=false
SFalse="没有对应的电子数据,不能归档案!"
end if
if CanGD then
openwithparm(w_ask,"确定要执行归档案吗?")
if message.stringparm="YES" then
//归档的备注字段
SDAMEMO=trim(mle_MEMO.text)
if len(SDAMEMO)>200 then
SDAMEMO=left(SDAMEMO,200)
end if
//检索关键词
SGJC=trim(Sle_GJC.text)
//生成档案编号
//取档案编码
SDACODE=trim(left(sle_daml.text,40))
L2=len(SDACODE)
wf_setstatus("请稍候......正在生成档案编号")
LMAX=0
declare CCODE cursor for select c01 from aindex_dacode using NowDB;
open CCODE;
fetch CCODE into :S1;
do while NowDB.sqlcode=0
if left(S1,l2)=SDACODE then
L1=long(right(S1,4))
if LMAX<L1 then LMAX=L1
end if
fetch CCODE into :S1;
loop
close CCODE;
LMAX=LMAX+1
SDACODEPPP=SDACODE+fill("0",4 - len(string(LMAX)))+string(LMAX)
insert into aindex_dacode values(:SDACODEPPP,0) using NowDB;
sle_CODE.text=SDACODEPPP
//建立索引,这里可以根据需要灵活处理
wf_setstatus("请稍候......正在建立索引")
SDACODE=SDACODEPPP
//工种索引
wf_sy_gz()
//人员索引
wf_sy_member()
//申报索引
wf_sy_sb()
//考务计划索引
wf_sy_kwjh()
//考务实施索引
wf_sy_kwss()
//索引单位
wf_sy_dw()
//写关键词
insert into daindex_gjc values(:SDACODE,:SGJC) using NowDB;
//电子数据进行保存
//将数据拷贝到保存的数据窗口
wf_setstatus("请稍候......正在处理电子数据")
dw_data.reset()
dw_1.RowsCopy(1,dw_1.rowcount(),Primary!, dw_data, 1, Primary!)
//数据写磁盘
if fileexists("c:\SGD.PSR") then
filedelete("c:\SGD.PSR")
end if
dw_data.SaveAs("c:\SGD.PSR",PSReport!,True)
//提取磁盘文件
B_PSR=gf_readdiskfiletoblob("c:\SGD.PSR")
wf_setstatus("请稍候......正在写入数据库")
//向档案记录表中插入归档记录
insert into dalist values(:SDACODEPPP,:SDAMC,1,:LDAJHID,:SDAJHMC,:SServerUser,:DT_NOW,'',:DT_NULL,:DT_NULL,'',:DT_NULL,0,'',:DT_NULL,'',:DT_NULL,'','','',0,'',:SCurrentTable_China,:SCurrentTable_English,:SDACODE,'') using NowDB;
//更新二进制文件
updateblob dalist
set c19=:B_PSR
where c01=:SDACODEPPP
using NowDB;
if fileexists("c:\SGD.PSR") then
filedelete("c:\SGD.PSR")
end if
//已经归档的记录在当前显示中应该删除
for LFOR=dw_1.rowcount() to 1 step -1
dw_1.deleterow(LFOR)
next
wf_setstatus("归档完毕!")
tab_1.tabpage_2.dw_2.retrieve()
openwithparm(w_messagebox,"归档完毕!")
end if
else
openwithparm(w_messagebox,SFalse)
end if
//建立检索就是建立检索字段与档案号码的对应关系,比如身份证号码、姓名与档案号码的对应关系的代码,函数名称为wf_sy_member():
//索引身份证号码和姓名,以便快速进行档案查询
long LFOR,L1
string SSFZ,SXM
String SSFZ_COL,SXM_COL
boolean CanSY
SSFZ_COL=""
SXM_COL=""
CanSY=true
//得到身份证号码、姓名在本数据表中对应列名
select c04 into :SSFZ_COL from dasy_tablefieldset where c02=:SCurrentTable_English and c03="身份证号码" using NowDB;
select c04 into :SXM_COL from dasy_tablefieldset where c02=:SCurrentTable_English and c03="姓名" using NowDB;
if not (isnull(SSFZ_COL) or SSFZ_COL='') then
//找到了对应关系就可以检索
for LFOR=1 to tab_1.tabpage_1.dw_1.rowcount()
yield()
wf_setstatus("请稍候......正在建立人员索引"+string(tab_1.tabpage_1.dw_1.rowcount())+"/"+string(LFOR))
CanSY=true
SSFZ=tab_1.tabpage_1.dw_1.getitemstring(LFOR,SSFZ_COL)
if isnull(SSFZ) or SSFZ='' then
CanSY=false
end if
if CanSY then
if not (isnull(SXM_COL) or SXM_COL='') then
//检查是否归档
SXM=tab_1.tabpage_1.dw_1.getitemstring(LFOR,SXM_COL)
if isnull(SXM) or SXM='' then
SXM="无"
end if
L1=0
select count(*) into :L1 from daindex_member where c01=:SDACODE and c02=:SSFZ and c03=:SXM using NowDB;
if L1=0 or isnull(L1) then
//没有身份证号码、姓名与档案号码的对应记录就插入新记录
insert into DAindex_member values(:SDACODE,:SSFZ,:SXM) using NowDB;
end if
end if
end if
next
end if
wf_setstatus("")
//调出具体档案记录的代码如下:
wf_setwintitle("浏览归档数据")
blob B_DATA
long LFOR,LFINDROW,LPPP
string S1
mystr_unit=Message.PowerObjectParm
SDACODE=mystr_unit.s4
//根据档案号码提出具体的二进制文件即归档的电子数据
selectblob c19 into :B_DATA from dalist where c01=:SDACODE using NowDB;
//写入磁盘
if fileexists("c:\ViewDA.psr") then
filedelete("c:\ViewDA.psr")
end if
//写入内存
gf_writeblobtofile("c:\ViewDA.psr",B_DATA)
//装载至数据窗口
dw_1.setredraw(false)
dw_1.dataobject="c:\ViewDA.psr"
dw_1.setredraw(true)
//dw_1.modify("datawindow.print.preview=Yes")
select c24 into :Stable from dalist where c01=:SDACODE using NowDB;
//执行定位
SWhere=mystr_unit.S1
if SWhere<>"" then
for LFOR=1 to dw_1.rowcount()
LFINDROW=dw_1.find(SWhere,1,dw_1.rowcount())
if LFINDROW>1 then
dw_1.selectrow(LFINDROW,true)
dw_1.scrolltorow(LFINDROW)
end if
next
end if
select c24 into :S1 from dalist where c01=:SDACODE using NowDB;
S1=UPPER(S1)
select c02 into :S1 from ostasystemvalue where c01=:S1 using NowDB;
if isnumber(S1) then
LPPP=long(S1)
if LPPP>0 then
for LFINDROW=1 to LPPP
if LFINDROW<10 then
dw_1.modify("c0"+string(LFINDROW)+".protect='1'")
else
dw_1.modify("c"+string(LFINDROW)+".protect='1'")
end if
next
end if
end if
//检查是否可以进行档案编辑
LFOR=0
select count(*) into :LFOR from ostasystemvalue where c01=:SServerUser and c02='档案编辑' using NowDB;
if LFOR>0 then
cb_new.visible=true
cb_del.visible=true
cb_save.visible=true
cb_new.enabled=true
cb_save.enabled=true
if LPPP>0 then
for LFINDROW=1 to LPPP
if LFINDROW<10 then
dw_1.modify("c0"+string(LFINDROW)+".protect='0'")
else
dw_1.modify("c"+string(LFINDROW)+".protect='0'")
end if
next
end if
else
cb_new.visible=false
cb_del.visible=false
cb_save.visible=false
cb_new.enabled=false
cb_save.enabled=false
end if
五、采用C/S模式
用Powerbuilder9结合MS SQL SERVER 2008设计开发实现,系统在扩展性方面能比较自由地发挥,在实际应用有较好的表现。
《电脑编程技巧与维护》2010年6月上