藥管理系統(tǒng)源碼實(shí)戰(zhàn):從部署到二次開(kāi)發(fā)的進(jìn)銷(xiāo)存核心設(shè)計(jì))
簡(jiǎn)介這是一套基于Java Web技術(shù)棧的醫(yī)藥管理系統(tǒng)后臺(tái)源碼面向計(jì)算機(jī)專(zhuān)業(yè)學(xué)生、課程設(shè)計(jì)開(kāi)發(fā)者及需要練手SSM/JSP項(xiàng)目的初學(xué)者可幫助快速搭建藥品進(jìn)銷(xiāo)存管理場(chǎng)景。系統(tǒng)圍繞藥品、類(lèi)別、庫(kù)存與銷(xiāo)售展開(kāi)實(shí)現(xiàn)了添加與查看藥品、高級(jí)查詢(xún)、庫(kù)存查看、類(lèi)別添加與統(tǒng)計(jì)、購(gòu)買(mǎi)藥品、銷(xiāo)售管理、進(jìn)貨需求管理及系統(tǒng)管理等模塊業(yè)務(wù)鏈路較為完整。壓縮包共162個(gè)文件約9.34MB以31個(gè)jsp頁(yè)面、30個(gè)java源文件、30個(gè)class編譯文件、26個(gè)jar依賴(lài)包及12個(gè)xml配置為主另含sql建庫(kù)腳本、properties配置與少量圖片資源結(jié)構(gòu)清晰便于二次開(kāi)發(fā)。開(kāi)發(fā)環(huán)境為JDK1.8搭配MySQL數(shù)據(jù)庫(kù)導(dǎo)入后即可對(duì)照源碼理解分層設(shè)計(jì)與數(shù)據(jù)庫(kù)交互邏輯。目前已有2058人學(xué)習(xí)下載適合作為課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)或Java Web入門(mén)實(shí)戰(zhàn)的參考案例。1. 醫(yī)藥管理系統(tǒng)源碼.zip一套能跑起來(lái)的進(jìn)銷(xiāo)存骨架長(zhǎng)什么樣很多做企業(yè)信息化的朋友拿到「醫(yī)藥管理系統(tǒng)源碼.zip」的第一反應(yīng)是解壓看目錄然后被幾十個(gè)文件夾和上百個(gè) PHP 文件勸退。我最初接觸這類(lèi)系統(tǒng)是在給一家區(qū)域連鎖藥房做二次開(kāi)發(fā)時(shí)當(dāng)時(shí)的需求很明確藥品批號(hào)要能追溯、近效期要能預(yù)警、GSP 規(guī)范里的首營(yíng)企業(yè)和首營(yíng)品種要能留痕。市面上的成品 SaaS 按門(mén)店收年費(fèi)數(shù)據(jù)還不在自己手里于是轉(zhuǎn)向源碼自建這條路。醫(yī)藥管理系統(tǒng)源碼本質(zhì)上是一套面向藥店、醫(yī)藥批發(fā)或門(mén)診藥房的進(jìn)銷(xiāo)存系統(tǒng)核心模塊通常包括藥品檔案、采購(gòu)入庫(kù)、銷(xiāo)售出庫(kù)、庫(kù)存盤(pán)點(diǎn)、批號(hào)效期管理和基礎(chǔ)報(bào)表。它和普通商品進(jìn)銷(xiāo)存的區(qū)別在于藥品有批號(hào)、有效期、批準(zhǔn)文號(hào)、生產(chǎn)廠家這些強(qiáng)監(jiān)管字段庫(kù)存不能只記數(shù)量還要記批次。這套源碼適合有 PHP 或 Java 基礎(chǔ)、想自己掌控?cái)?shù)據(jù)和二次開(kāi)發(fā)節(jié)奏的團(tuán)隊(duì)也適合作為課程設(shè)計(jì)或畢業(yè)設(shè)計(jì)的參考工程。下面我按實(shí)際落地順序把選型、部署、核心表結(jié)構(gòu)和踩坑點(diǎn)拆開(kāi)講。2. 拿到源碼先別急著跑技術(shù)棧盤(pán)點(diǎn)和環(huán)境選型2.1 從目錄結(jié)構(gòu)判斷這套源碼的技術(shù)棧解壓后先看根目錄不要急著找 index.php。我一般按這個(gè)順序掃一遍有沒(méi)有composer.json或pom.xml有沒(méi)有application或app目錄有沒(méi)有sql文件夾有沒(méi)有README或install目錄。這四個(gè)位置基本能確定技術(shù)棧和部署方式。常見(jiàn)的醫(yī)藥管理系統(tǒng)源碼分兩類(lèi)。一類(lèi)是 ThinkPHP 或 Laravel 寫(xiě)的 PHP 項(xiàng)目目錄里會(huì)有application、public、think或artisan另一類(lèi)是 SpringBoot 寫(xiě)的 Java 項(xiàng)目會(huì)有src/main/java、pom.xml、application.yml。熱搜詞里「php源碼」和「java課程設(shè)計(jì)案例源碼」出現(xiàn)頻率很高說(shuō)明這兩類(lèi)都是主流。判斷清楚再選環(huán)境別用 PHP 的環(huán)境去跑 Java 包。# 查看根目錄關(guān)鍵文件快速判斷技術(shù)棧 ls -la # 有 composer.json - PHP 項(xiàng)目 # 有 pom.xml 或 build.gradle - Java 項(xiàng)目 # 有 package.json 且無(wú)后端框架 - 可能只是前端模板 find . -maxdepth 2 -name *.sql -o -name application.yml -o -name config.php這段命令的作用是快速定位配置文件和數(shù)據(jù)庫(kù)腳本。-maxdepth 2限制搜索深度避免在大目錄里卡住。如果找到.sql文件說(shuō)明作者提供了建表腳本這是最省事的情況如果只有.sql的碎片或沒(méi)有就要從實(shí)體類(lèi)反推表結(jié)構(gòu)工作量會(huì)大很多。2.2 PHP 和 Java 兩條路的環(huán)境準(zhǔn)備如果確認(rèn)是 PHP 項(xiàng)目推薦 PHP 7.4 到 8.1 之間MySQL 5.7 或 8.0。PHP 8.2 以上有些老源碼會(huì)因?yàn)閯?dòng)態(tài)屬性廢棄而報(bào)錯(cuò)這是血淚經(jīng)驗(yàn)。用寶塔或 phpstudy 搭環(huán)境最快但生產(chǎn)環(huán)境我建議手動(dòng)配 Nginx PHP-FPM因?yàn)獒t(yī)藥系統(tǒng)涉及數(shù)據(jù)合規(guī)面板工具的默認(rèn)配置往往開(kāi)了不必要的端口。Java 項(xiàng)目則看pom.xml里的spring-boot-starter-parent版本。如果是 2.xJDK 用 8 或 11如果是 3.xJDK 必須 17 以上。數(shù)據(jù)庫(kù)連接池常見(jiàn) Druid 或 HikariCP配置文件里搜url:就能找到數(shù)據(jù)庫(kù)地址。下面是一個(gè)典型的 PHP 項(xiàng)目數(shù)據(jù)庫(kù)配置片段改完就能連庫(kù)。// config/database.php 常見(jiàn)結(jié)構(gòu) return [ type mysql, hostname 127.0.0.1, database medicine_db, // 數(shù)據(jù)庫(kù)名按 sql 腳本里的 CREATE DATABASE 填 username med_user, // 不要用 root單獨(dú)建賬號(hào) password YourStrongPwd, // 生產(chǎn)環(huán)境必須強(qiáng)密碼 hostport 3306, charset utf8mb4, // 藥品名有生僻字必須 utf8mb4 prefix med_, // 表前綴和 sql 腳本保持一致 ];參數(shù)說(shuō)明charset必須是utf8mb4因?yàn)樗幤吠ㄓ妹镉小?」「啶」這類(lèi)字utf8存進(jìn)去會(huì)變問(wèn)號(hào)。prefix要和導(dǎo)入 SQL 時(shí)的表前綴一致不一致會(huì)報(bào)「表不存在」。username單獨(dú)建賬號(hào)并只授權(quán)該庫(kù)避免源碼里有后門(mén)時(shí)被拖全庫(kù)。2.3 導(dǎo)入數(shù)據(jù)庫(kù)和首次訪問(wèn)的完整流程建庫(kù)、導(dǎo)表、改配置、配偽靜態(tài)這四步順序不能亂。先建一個(gè)空庫(kù)字符集選utf8mb4_general_ci然后用命令行導(dǎo)入 SQL不要用 phpMyAdmin 導(dǎo)大文件容易超時(shí)截?cái)唷? 1. 建庫(kù) mysql -u root -p -e CREATE DATABASE medicine_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; # 2. 導(dǎo)入表結(jié)構(gòu)和初始數(shù)據(jù) mysql -u root -p medicine_db install/medicine_db.sql # 3. 檢查表數(shù)量正常醫(yī)藥系統(tǒng)在 30 到 60 張表之間 mysql -u root -p medicine_db -e SHOW TABLES; | wc -l導(dǎo)入后如果表數(shù)量明顯偏少比如只有十幾張說(shuō)明 SQL 腳本不完整可能作者只導(dǎo)了部分表。這時(shí)候要去install目錄或doc目錄找有沒(méi)有分卷的 SQL 文件。首次訪問(wèn)一般是http://你的域名/install或http://你的域名/public/index.php具體看框架。ThinkPHP 的入口在public下Nginx 要配偽靜態(tài)否則除首頁(yè)外全是 404。提示部署完成后第一件事是改默認(rèn)管理員密碼第二件事是刪掉install目錄。我見(jiàn)過(guò)太多源碼裝完不刪安裝目錄被人重新跑一遍安裝流程直接接管后臺(tái)。3. 藥品、批號(hào)、庫(kù)存三張核心表怎么設(shè)計(jì)才算能用3.1 藥品檔案表批準(zhǔn)文號(hào)和通用名的字段取舍醫(yī)藥管理系統(tǒng)的數(shù)據(jù)地基是藥品檔案表。普通進(jìn)銷(xiāo)存一張goods表就夠了但醫(yī)藥系統(tǒng)必須拆出「藥品通用名」「商品名」「批準(zhǔn)文號(hào)」「生產(chǎn)企業(yè)」「劑型」「規(guī)格」這些字段。我見(jiàn)過(guò)一些源碼把通用名和商品名混在一個(gè)字段里結(jié)果做 GSP 報(bào)表時(shí)根本拆不出來(lái)。CREATE TABLE med_drug ( id int NOT NULL AUTO_INCREMENT, drug_code varchar(32) NOT NULL COMMENT 內(nèi)部編碼, generic_name varchar(128) NOT NULL COMMENT 通用名如阿莫西林膠囊, trade_name varchar(128) DEFAULT NULL COMMENT 商品名, approval_number varchar(64) NOT NULL COMMENT 批準(zhǔn)文號(hào)國(guó)藥準(zhǔn)字Hxxxx, manufacturer varchar(128) NOT NULL COMMENT 生產(chǎn)企業(yè), dosage_form varchar(32) DEFAULT NULL COMMENT 劑型, spec varchar(64) DEFAULT NULL COMMENT 規(guī)格, is_prescription tinyint(1) DEFAULT 0 COMMENT 是否處方藥, storage_condition varchar(64) DEFAULT NULL COMMENT 儲(chǔ)存條件, PRIMARY KEY (id), UNIQUE KEY uk_approval (approval_number), KEY idx_generic (generic_name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;approval_number加唯一索引因?yàn)橐粋€(gè)批準(zhǔn)文號(hào)對(duì)應(yīng)一個(gè)藥品重復(fù)錄入會(huì)導(dǎo)致批號(hào)追溯混亂。generic_name加普通索引因?yàn)殇N(xiāo)售開(kāi)單時(shí)按通用名搜索是最高頻操作。is_prescription字段決定銷(xiāo)售時(shí)是否強(qiáng)制登記處方信息這是醫(yī)藥系統(tǒng)區(qū)別于普通商城的硬性邏輯。3.2 批號(hào)庫(kù)存表為什么不能只存一個(gè)數(shù)量普通庫(kù)存表存「商品 ID 數(shù)量」醫(yī)藥系統(tǒng)必須存「藥品 ID 批號(hào) 生產(chǎn)日期 有效期 數(shù)量」。同一盒阿莫西林批號(hào) A 和批號(hào) B 的效期不同出庫(kù)時(shí)要按先進(jìn)先出或近效期先出。如果源碼里庫(kù)存表沒(méi)有批號(hào)字段這套系統(tǒng)基本不能用于真實(shí)藥房。CREATE TABLE med_stock_batch ( id bigint NOT NULL AUTO_INCREMENT, drug_id int NOT NULL, batch_no varchar(64) NOT NULL COMMENT 生產(chǎn)批號(hào), production_date date DEFAULT NULL, expiry_date date NOT NULL COMMENT 有效期至, quantity int NOT NULL DEFAULT 0, warehouse_id int NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_drug_batch_wh (drug_id,batch_no,warehouse_id), KEY idx_expiry (expiry_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;uk_drug_batch_wh保證同一藥品同一批號(hào)在同一倉(cāng)庫(kù)只有一條記錄入庫(kù)時(shí)用ON DUPLICATE KEY UPDATE quantity quantity ?累加。idx_expiry是近效期預(yù)警的查詢(xún)索引沒(méi)有這個(gè)索引效期報(bào)表在幾萬(wàn)條庫(kù)存下會(huì)慢到不可用。3.3 入庫(kù)出庫(kù)單主表和明細(xì)表的事務(wù)邊界采購(gòu)入庫(kù)和銷(xiāo)售出庫(kù)都是「一張主單 多條明細(xì)」的結(jié)構(gòu)。主表存供應(yīng)商、單據(jù)號(hào)、總金額、狀態(tài)明細(xì)表存藥品、批號(hào)、數(shù)量、單價(jià)。關(guān)鍵點(diǎn)是出庫(kù)時(shí)扣減庫(kù)存和寫(xiě)明細(xì)必須在同一個(gè)事務(wù)里否則會(huì)出現(xiàn)單據(jù)寫(xiě)了但庫(kù)存沒(méi)扣或者庫(kù)存扣了單據(jù)沒(méi)寫(xiě)。// 出庫(kù)事務(wù)示例ThinkPHP 風(fēng)格 Db::startTrans(); try { $orderId Db::name(sale_order)-insertGetId($orderData); foreach ($items as $item) { // 扣減對(duì)應(yīng)批號(hào)庫(kù)存quantity 出庫(kù)量才允許 $affected Db::name(stock_batch) -where(drug_id, $item[drug_id]) -where(batch_no, $item[batch_no]) -where(quantity, , $item[qty]) -dec(quantity, $item[qty]) -update(); if (!$affected) { throw new Exception(批號(hào)庫(kù)存不足 . $item[batch_no]); } Db::name(sale_order_item)-insert($item); } Db::commit(); } catch (Exception $e) { Db::rollback(); return json([code 0, msg $e-getMessage()]); }where(quantity, , $item[qty])這個(gè)條件很關(guān)鍵它把庫(kù)存檢查放在 UPDATE 語(yǔ)句里利用數(shù)據(jù)庫(kù)行鎖避免并發(fā)超賣(mài)。如果先 SELECT 查庫(kù)存再 UPDATE兩個(gè)收銀臺(tái)同時(shí)出庫(kù)同一批號(hào)就會(huì)扣成負(fù)數(shù)。dec是 ThinkPHP 的原子遞減方法等價(jià)于quantity quantity - N。注意事務(wù)里不要做遠(yuǎn)程調(diào)用或文件寫(xiě)入否則事務(wù)持有時(shí)間過(guò)長(zhǎng)高并發(fā)下會(huì)鎖等待。打印小票、發(fā)短信這類(lèi)操作放到事務(wù)提交之后。4. 從源碼到能用的系統(tǒng)部署、初始化和權(quán)限配置4.1 后臺(tái)菜單和權(quán)限節(jié)點(diǎn)怎么對(duì)應(yīng)醫(yī)藥管理系統(tǒng)的后臺(tái)通常有管理員、店長(zhǎng)、收銀員、庫(kù)管這幾個(gè)角色。源碼里的權(quán)限控制一般基于「節(jié)點(diǎn)」實(shí)現(xiàn)每個(gè)控制器方法對(duì)應(yīng)一個(gè)權(quán)限節(jié)點(diǎn)角色勾選節(jié)點(diǎn)后才有權(quán)訪問(wèn)。部署后第一件事是進(jìn)「權(quán)限管理」把菜單和節(jié)點(diǎn)對(duì)齊否則會(huì)出現(xiàn)菜單看得見(jiàn)但點(diǎn)進(jìn)去 403 的情況。角色藥品檔案采購(gòu)入庫(kù)銷(xiāo)售出庫(kù)庫(kù)存盤(pán)點(diǎn)報(bào)表管理員增刪改查增刪改查增刪改查增刪改查全部店長(zhǎng)查改增查增查增查本店收銀員只讀無(wú)增查無(wú)無(wú)庫(kù)管查改增刪改查只讀增刪改查庫(kù)存類(lèi)這張表是我給連鎖藥房配權(quán)限時(shí)的實(shí)際方案。收銀員不給采購(gòu)權(quán)限庫(kù)管不給銷(xiāo)售改價(jià)權(quán)限這是內(nèi)控基本要求。源碼如果只有「超級(jí)管理員」一個(gè)角色需要自己在角色表里加記錄并在節(jié)點(diǎn)表里補(bǔ)全控制器方法名。4.2 初始化數(shù)據(jù)倉(cāng)庫(kù)、供應(yīng)商、藥品分類(lèi)系統(tǒng)裝好后是空庫(kù)直接開(kāi)單會(huì)報(bào)錯(cuò)。按這個(gè)順序初始化先建倉(cāng)庫(kù)至少一個(gè)「主倉(cāng)庫(kù)」再建藥品分類(lèi)處方藥、非處方藥、中藥飲片、醫(yī)療器械再建供應(yīng)商和客戶(hù)最后錄藥品檔案。藥品檔案可以手工錄也可以用 Excel 導(dǎo)入源碼一般帶導(dǎo)入模板。# 檢查初始化數(shù)據(jù)是否完整 mysql -u med_user -p medicine_db -e SELECT 倉(cāng)庫(kù) AS type, COUNT(*) AS cnt FROM med_warehouse UNION ALL SELECT 分類(lèi), COUNT(*) FROM med_category UNION ALL SELECT 供應(yīng)商, COUNT(*) FROM med_supplier UNION ALL SELECT 藥品, COUNT(*) FROM med_drug;如果倉(cāng)庫(kù)數(shù)量為 0先去后臺(tái)「?jìng)}庫(kù)管理」加一條。如果藥品為 0 但分類(lèi)有數(shù)據(jù)說(shuō)明導(dǎo)入模板的列名和表字段沒(méi)對(duì)上檢查 Excel 表頭是否包含「通用名」「批準(zhǔn)文號(hào)」「生產(chǎn)企業(yè)」這三列缺一列都會(huì)導(dǎo)入失敗。4.3 近效期預(yù)警和批號(hào)追溯的驗(yàn)證方法部署完不算完要驗(yàn)證兩個(gè)醫(yī)藥系統(tǒng)的核心能力。第一近效期預(yù)警錄一個(gè)有效期在 90 天內(nèi)的批號(hào)看首頁(yè)或報(bào)表是否出現(xiàn)預(yù)警。第二批號(hào)追溯隨便選一個(gè)批號(hào)看能不能查到它的入庫(kù)單、出庫(kù)單、當(dāng)前庫(kù)存和流向客戶(hù)。-- 批號(hào)全鏈路追溯查詢(xún) SELECT 入庫(kù) AS flow, i.order_no, i.create_time, i.quantity FROM med_purchase_item i WHERE i.batch_no 20240501A UNION ALL SELECT 出庫(kù), o.order_no, o.create_time, o.quantity FROM med_sale_item o WHERE o.batch_no 20240501A;這條 SQL 把某批號(hào)的入庫(kù)和出庫(kù)記錄合并展示。如果查出來(lái)只有入庫(kù)沒(méi)有出庫(kù)但庫(kù)存顯示為 0說(shuō)明源碼的庫(kù)存扣減邏輯有 bug可能出庫(kù)時(shí)沒(méi)寫(xiě)明細(xì)或者寫(xiě)錯(cuò)了批號(hào)。這種情況在二次開(kāi)發(fā)過(guò)的源碼里很常見(jiàn)必須逐單核對(duì)。5. 二次開(kāi)發(fā)避坑那些讓我加班到凌晨的坑5.1 現(xiàn)象入庫(kù)后庫(kù)存不增加但單據(jù)顯示成功原因庫(kù)存表用了drug_id warehouse_id做唯一鍵沒(méi)有把batch_no納入唯一鍵導(dǎo)致同一藥品不同批號(hào)互相覆蓋。解決檢查med_stock_batch的唯一索引必須是drug_id batch_no warehouse_id三字段聯(lián)合。如果源碼建表時(shí)漏了批號(hào)需要改表結(jié)構(gòu)并重算歷史庫(kù)存。5.2 現(xiàn)象銷(xiāo)售開(kāi)單搜索藥品輸入通用名搜不到原因藥品檔案的generic_name字段沒(méi)有建索引或者搜索用的是LIKE %關(guān)鍵詞%導(dǎo)致全表掃描數(shù)據(jù)量一大就超時(shí)。解決先加索引再把搜索邏輯改成前綴匹配LIKE 關(guān)鍵詞%或者接入全文索引。如果源碼用的是FIND_IN_SET存多關(guān)鍵詞建議改成獨(dú)立搜索表。5.3 現(xiàn)象并發(fā)出庫(kù)時(shí)庫(kù)存扣成負(fù)數(shù)原因出庫(kù)邏輯先SELECT查庫(kù)存再UPDATE扣減兩個(gè)操作之間沒(méi)有鎖。解決把庫(kù)存檢查合并進(jìn)UPDATE的WHERE條件如第 3 章示例或者用SELECT ... FOR UPDATE鎖行。前者性能更好后者適合扣減邏輯復(fù)雜的場(chǎng)景。5.4 現(xiàn)象PHP 8 下后臺(tái)白屏日志報(bào)動(dòng)態(tài)屬性廢棄原因老源碼用了$this-xxx $yyy動(dòng)態(tài)賦值PHP 8.2 起標(biāo)記為廢棄部分框架會(huì)拋異常。解決降級(jí)到 PHP 7.4 或 8.1或者在模型基類(lèi)加#[\AllowDynamicProperties]注解。生產(chǎn)環(huán)境不建議為了跑老源碼而長(zhǎng)期停留在低版本最好逐步重構(gòu)。5.5 現(xiàn)象導(dǎo)入 Excel 藥品檔案中文全部亂碼原因Excel 默認(rèn)編碼是 GBK而數(shù)據(jù)庫(kù)是 utf8mb4導(dǎo)入時(shí)沒(méi)有轉(zhuǎn)碼。解決導(dǎo)入前用iconv(GBK, UTF-8, $value)轉(zhuǎn)碼或者要求模板保存為 CSV UTF-8 格式。我一般直接在導(dǎo)入類(lèi)里統(tǒng)一轉(zhuǎn)碼避免用戶(hù)操作差異。6. 讓這套源碼真正值錢(qián)的三個(gè)進(jìn)階動(dòng)作第一個(gè)動(dòng)作是給批號(hào)庫(kù)存加「鎖定庫(kù)存」字段。銷(xiāo)售開(kāi)單時(shí)先鎖庫(kù)存付款后再實(shí)扣取消訂單則釋放。這樣能解決「下單未付款期間庫(kù)存被其他單占用」的問(wèn)題。實(shí)現(xiàn)上在med_stock_batch加locked_quantity可用庫(kù)存等于quantity - locked_quantity出庫(kù)時(shí)校驗(yàn)可用庫(kù)存。第二個(gè)動(dòng)作是把近效期預(yù)警做成定時(shí)任務(wù)而不是每次打開(kāi)首頁(yè)才查。用 crontab 每天凌晨跑一次把 90 天內(nèi)到期的批號(hào)寫(xiě)進(jìn)預(yù)警表并推送給庫(kù)管。這樣即使沒(méi)人登錄后臺(tái)預(yù)警也不會(huì)漏。# 每天凌晨 2 點(diǎn)執(zhí)行效期掃描 0 2 * * * /usr/bin/php /www/medicine/think expiry:scan /var/log/expiry.log 21第三個(gè)動(dòng)作是給關(guān)鍵操作加審計(jì)日志。藥品檔案修改、庫(kù)存手動(dòng)調(diào)整、價(jià)格改動(dòng)這三類(lèi)操作必須記錄操作人、時(shí)間、修改前后值。GSP 檢查時(shí)這是必查項(xiàng)臨時(shí)補(bǔ)日志根本來(lái)不及。源碼如果沒(méi)有審計(jì)表自己加一張med_audit_log在模型事件里統(tǒng)一寫(xiě)入。我自己的習(xí)慣是拿到任何一套醫(yī)藥管理系統(tǒng)源碼先跑通「采購(gòu)入庫(kù) → 銷(xiāo)售出庫(kù) → 批號(hào)追溯」這條最小閉環(huán)再談二次開(kāi)發(fā)。閉環(huán)跑不通后面加再多功能都是空中樓閣。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取