diff --git a/apps/web/public/inventory.wasm b/apps/web/public/inventory.wasm
new file mode 100644
index 0000000..ec18f60
Binary files /dev/null and b/apps/web/public/inventory.wasm differ
diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx
index 2e4d953..b888716 100644
--- a/apps/web/src/App.tsx
+++ b/apps/web/src/App.tsx
@@ -4,6 +4,7 @@ import { ConfigProvider, theme as antdTheme, Spin } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import MainLayout from './layouts/MainLayout';
import Login from './pages/Login';
+import { ErrorBoundary } from './components/ErrorBoundary';
import { useAuthStore } from './stores/auth';
import { useAppStore } from './stores/app';
@@ -133,6 +134,7 @@ export default function App() {
element={
+
}>
} />
@@ -151,6 +153,7 @@ export default function App() {
} />
+
}
diff --git a/crates/erp-plugin/src/data_service.rs b/crates/erp-plugin/src/data_service.rs
index e5455bc..c12e236 100644
--- a/crates/erp-plugin/src/data_service.rs
+++ b/crates/erp-plugin/src/data_service.rs
@@ -527,6 +527,7 @@ impl PluginDataService {
db: &sea_orm::DatabaseConnection,
filter: Option,
search: Option,
+ scope: Option,
) -> AppResult {
let info = resolve_entity_info(plugin_id, entity_name, tenant_id, db).await?;
@@ -543,7 +544,7 @@ impl PluginDataService {
}
};
- let (sql, values) = DynamicTableManager::build_filtered_count_sql(
+ let (mut sql, mut values) = DynamicTableManager::build_filtered_count_sql(
&info.table_name,
tenant_id,
filter,
@@ -551,6 +552,13 @@ impl PluginDataService {
)
.map_err(|e| AppError::Validation(e))?;
+ // 合并数据权限条件
+ let scope_condition = build_scope_sql(&scope, &info.generated_fields);
+ if !scope_condition.0.is_empty() {
+ sql = merge_scope_condition(sql, &scope_condition);
+ values.extend(scope_condition.1);
+ }
+
#[derive(FromQueryResult)]
struct CountResult {
count: i64,
@@ -578,10 +586,11 @@ impl PluginDataService {
db: &sea_orm::DatabaseConnection,
group_by_field: &str,
filter: Option,
+ scope: Option,
) -> AppResult> {
let info = resolve_entity_info(plugin_id, entity_name, tenant_id, db).await?;
- let (sql, values) = DynamicTableManager::build_aggregate_sql(
+ let (mut sql, mut values) = DynamicTableManager::build_aggregate_sql(
&info.table_name,
tenant_id,
group_by_field,
@@ -589,6 +598,13 @@ impl PluginDataService {
)
.map_err(|e| AppError::Validation(e))?;
+ // 合并数据权限条件
+ let scope_condition = build_scope_sql(&scope, &info.generated_fields);
+ if !scope_condition.0.is_empty() {
+ sql = merge_scope_condition(sql, &scope_condition);
+ values.extend(scope_condition.1);
+ }
+
#[derive(FromQueryResult)]
struct AggRow {
key: Option,
@@ -621,7 +637,7 @@ impl PluginDataService {
filter: Option,
) -> AppResult> {
// TODO: 未来版本添加 Redis 缓存层
- Self::aggregate(plugin_id, entity_name, tenant_id, db, group_by_field, filter).await
+ Self::aggregate(plugin_id, entity_name, tenant_id, db, group_by_field, filter, None).await
}
/// 时间序列聚合 — 按时间字段截断为 day/week/month 统计计数
@@ -634,10 +650,11 @@ impl PluginDataService {
time_grain: &str,
start: Option,
end: Option,
+ scope: Option,
) -> AppResult> {
let info = resolve_entity_info(plugin_id, entity_name, tenant_id, db).await?;
- let (sql, values) = DynamicTableManager::build_timeseries_sql(
+ let (mut sql, mut values) = DynamicTableManager::build_timeseries_sql(
&info.table_name,
tenant_id,
time_field,
@@ -647,6 +664,13 @@ impl PluginDataService {
)
.map_err(|e| AppError::Validation(e))?;
+ // 合并数据权限条件
+ let scope_condition = build_scope_sql(&scope, &info.generated_fields);
+ if !scope_condition.0.is_empty() {
+ sql = merge_scope_condition(sql, &scope_condition);
+ values.extend(scope_condition.1);
+ }
+
#[derive(FromQueryResult)]
struct TsRow {
period: Option,
diff --git a/crates/erp-plugin/src/handler/data_handler.rs b/crates/erp-plugin/src/handler/data_handler.rs
index e6d0104..ce16f7c 100644
--- a/crates/erp-plugin/src/handler/data_handler.rs
+++ b/crates/erp-plugin/src/handler/data_handler.rs
@@ -390,6 +390,11 @@ where
let fine_perm = compute_permission_code(&manifest_id, &entity, "list");
require_permission(&ctx, &fine_perm)?;
+ // 解析数据权限范围
+ let scope = resolve_data_scope(
+ &ctx, &manifest_id, &entity, &fine_perm, &state.db,
+ ).await?;
+
// 解析 filter JSON
let filter: Option = params
.filter
@@ -403,6 +408,7 @@ where
&state.db,
filter,
params.search,
+ scope,
)
.await?;
@@ -434,6 +440,11 @@ where
let fine_perm = compute_permission_code(&manifest_id, &entity, "list");
require_permission(&ctx, &fine_perm)?;
+ // 解析数据权限范围
+ let scope = resolve_data_scope(
+ &ctx, &manifest_id, &entity, &fine_perm, &state.db,
+ ).await?;
+
// 解析 filter JSON
let filter: Option = params
.filter
@@ -447,6 +458,7 @@ where
&state.db,
¶ms.group_by,
filter,
+ scope,
)
.await?;
@@ -483,6 +495,11 @@ where
let fine_perm = compute_permission_code(&manifest_id, &entity, "list");
require_permission(&ctx, &fine_perm)?;
+ // 解析数据权限范围
+ let scope = resolve_data_scope(
+ &ctx, &manifest_id, &entity, &fine_perm, &state.db,
+ ).await?;
+
let result = PluginDataService::timeseries(
plugin_id,
&entity,
@@ -492,6 +509,7 @@ where
¶ms.time_grain,
params.start,
params.end,
+ scope,
)
.await?;