refactor: 删除 product_type_config(运营商产品类型配置)功能
- 删除 models/product_type_config.json
- 删除 json/product_type_config_list.json (CRUD定义)
- 删除 wwwroot/product_type_config_manage.ui 和 product_type_config_list/ 目录
- 删除 wwwroot/api/product_type_config_{create,update,delete}.dspy
- core.py: 移除 get_operator_config/set_operator_config 方法
- core.py: get_product_detail 不再查询 operator_config
- __init__.py: 移除 wrapper 函数和 env 注册
- product_detail.dspy: 移除 operator_config 查询逻辑
- scripts/load_path.py: 移除所有 product_type_config 权限路径
- menu.ui: 移除"运营商配置"菜单项
- index.ui: 移除"运营商配置"卡片,更新标题描述
- README.md: 移除相关文档
This commit is contained in:
parent
6dae1676ef
commit
1438de9d58
@ -17,7 +17,6 @@ product_management 是产品生命周期的中枢,负责:
|
||||
|------|------|
|
||||
| `product_category` | 产品类别树(parent_id 层级关系,resource_module 标记来源模块) |
|
||||
| `product` | 产品注册表(resource_ref_id 关联资源模块内部ID) |
|
||||
| `product_type_config` | 产品类型配置(运营者级别的 JSON 配置) |
|
||||
| `product_resource` | 产品-资源绑定(一个产品可绑定多个资源,含配额和溢出产品) |
|
||||
| `product_resource_supplier` | 资源绑定的供应商路由(优先级+权重) |
|
||||
| `product_subscription` | 产品订阅(月度/按量,含配额跟踪和溢出计费) |
|
||||
@ -118,12 +117,10 @@ def load_product_management():
|
||||
# 基础 CRUD
|
||||
env.get_product_brief = get_product_brief
|
||||
env.get_product_detail = get_product_detail
|
||||
env.get_category_tree = get_category_tree
|
||||
env.get_products_by_category = get_products_by_category
|
||||
env.purchase_product = purchase_product
|
||||
env.use_product = use_product
|
||||
env.get_operator_config = get_operator_config
|
||||
env.set_operator_config = set_operator_config
|
||||
env.get_category_tree = get_category_tree
|
||||
env.get_products_by_category = get_products_by_category
|
||||
env.import_categories_and_products = import_categories_and_products
|
||||
# 资源模块接口调度
|
||||
env.get_product_display_info = get_product_display_info
|
||||
@ -255,7 +252,6 @@ product_management/
|
||||
│ ├── product_resource.json
|
||||
│ ├── product_resource_supplier.json
|
||||
│ ├── product_subscription.json
|
||||
│ ├── product_type_config.json
|
||||
│ └── product_usage_log.json
|
||||
├── product_management/
|
||||
│ ├── __init__.py # ServerEnv 注册 + 入口函数
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
{
|
||||
"tblname": "product_type_config",
|
||||
"alias": "product_type_config_list",
|
||||
"title": "运营商产品类型配置",
|
||||
"params": {
|
||||
"sortby": ["created_at desc"],
|
||||
"logined_userorgid": "org_id",
|
||||
"logined_userid": "operator_id",
|
||||
"data_filter": {
|
||||
"AND": [
|
||||
{"field": "config_name", "op": "LIKE", "var": "config_name"}
|
||||
]
|
||||
},
|
||||
"filter_labels": {
|
||||
"config_name": "配置名称"
|
||||
},
|
||||
"browserfields": {
|
||||
"exclouded": [],
|
||||
"alters": {
|
||||
"category_id": {
|
||||
"uitype": "code",
|
||||
"dataurl": "{{entire_url('../api/category_options.dspy')}}",
|
||||
"datamethod": "GET"
|
||||
},
|
||||
"enabled_flg": {
|
||||
"uitype": "code",
|
||||
"data": [
|
||||
{"value": "1", "text": "启用"},
|
||||
{"value": "0", "text": "禁用"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"editexclouded": ["operator_id", "created_by", "created_at", "updated_at"],
|
||||
"editable": {
|
||||
"new_data_url": "{{entire_url('../api/product_type_config_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('../api/product_type_config_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('../api/product_type_config_delete.dspy')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,122 +0,0 @@
|
||||
{
|
||||
"summary": [
|
||||
{
|
||||
"name": "product_type_config",
|
||||
"title": "运营商产品类型配置",
|
||||
"primary": [
|
||||
"id"
|
||||
],
|
||||
"catelog": "relation"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"title": "主键ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "operator_id",
|
||||
"title": "运营商用户ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"title": "所属机构ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "category_id",
|
||||
"title": "产品类别ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "config_name",
|
||||
"title": "配置名称",
|
||||
"type": "str",
|
||||
"length": 255,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "config_json",
|
||||
"title": "配置内容",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "enabled_flg",
|
||||
"title": "是否启用",
|
||||
"type": "char",
|
||||
"length": 1,
|
||||
"default": "1"
|
||||
},
|
||||
{
|
||||
"name": "created_by",
|
||||
"title": "创建人",
|
||||
"type": "str",
|
||||
"length": 32
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"title": "创建时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "updated_at",
|
||||
"title": "更新时间",
|
||||
"type": "timestamp",
|
||||
"nullable": "no"
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"name": "idx_ptc_org_opr",
|
||||
"idxtype": "index",
|
||||
"idxfields": [
|
||||
"org_id",
|
||||
"operator_id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "idx_ptc_org_cat",
|
||||
"idxtype": "unique",
|
||||
"idxfields": [
|
||||
"org_id",
|
||||
"operator_id",
|
||||
"category_id",
|
||||
"config_name"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "idx_ptc_enabled",
|
||||
"idxtype": "index",
|
||||
"idxfields": [
|
||||
"enabled_flg"
|
||||
]
|
||||
}
|
||||
],
|
||||
"codes": [
|
||||
{
|
||||
"field": "category_id",
|
||||
"table": "product_category",
|
||||
"valuefield": "id",
|
||||
"textfield": "name",
|
||||
"cond": "has_product='1' AND status='1'"
|
||||
},
|
||||
{
|
||||
"field": "enabled_flg",
|
||||
"table": "appcodes_kv",
|
||||
"valuefield": "k",
|
||||
"textfield": "v",
|
||||
"cond": "parentid='enabled_flg'"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -55,17 +55,6 @@ async def get_products_by_category(category_id, status='1'):
|
||||
return await manager.get_products_by_category(category_id, status)
|
||||
|
||||
|
||||
async def get_operator_config(category_id, user_id=None):
|
||||
"""Get operator configuration for a category."""
|
||||
manager = get_manager()
|
||||
return await manager.get_operator_config(category_id, user_id)
|
||||
|
||||
|
||||
async def set_operator_config(category_id, config_name, config_json, user_id=None, org_id=None):
|
||||
"""Create or update operator configuration for a category."""
|
||||
manager = get_manager()
|
||||
return await manager.set_operator_config(category_id, config_name, config_json, user_id, org_id)
|
||||
|
||||
|
||||
async def import_categories_and_products(resource_module, org_id, parent_category_id, user_id):
|
||||
"""Import sub-categories and products from a resource module."""
|
||||
@ -120,8 +109,7 @@ def load_product_management():
|
||||
env.use_product = use_product
|
||||
env.get_category_tree = get_category_tree
|
||||
env.get_products_by_category = get_products_by_category
|
||||
env.get_operator_config = get_operator_config
|
||||
env.set_operator_config = set_operator_config
|
||||
|
||||
env.import_categories_and_products = import_categories_and_products
|
||||
# Resource module interface dispatchers
|
||||
env.get_product_display_info = get_product_display_info
|
||||
|
||||
@ -177,7 +177,7 @@ class ProductManager:
|
||||
async def get_product_detail(self, product_id=None, product_code=None, org_id=None, user_id=None):
|
||||
"""Get product detail for current org (reseller).
|
||||
|
||||
Returns product_info + category_info + operator_config + extra_parsed.
|
||||
Returns product_info + category_info + extra_parsed.
|
||||
"""
|
||||
if not org_id:
|
||||
org_id = self._get_current_org_id()
|
||||
@ -225,29 +225,6 @@ class ProductManager:
|
||||
extra_parsed = {'_raw': extra_str}
|
||||
product_info['extra_parsed'] = extra_parsed
|
||||
|
||||
# Get operator config for this category
|
||||
config_sql = """SELECT * FROM product_type_config
|
||||
WHERE category_id = ${category_id}$
|
||||
AND org_id = ${org_id}$
|
||||
AND enabled_flg = '1'
|
||||
AND (operator_id = ${user_id}$ OR operator_id = '0')
|
||||
ORDER BY created_at DESC LIMIT 1"""
|
||||
config_rows = await sor.sqlExe(config_sql, {
|
||||
'category_id': product_info['category_id'],
|
||||
'org_id': org_id,
|
||||
'user_id': user_id
|
||||
})
|
||||
|
||||
operator_config = {}
|
||||
if config_rows:
|
||||
operator_config = dict(config_rows[0])
|
||||
config_json = operator_config.get('config_json', '')
|
||||
if config_json:
|
||||
try:
|
||||
operator_config['config_parsed'] = json.loads(config_json)
|
||||
except:
|
||||
operator_config['config_parsed'] = {}
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'data': {
|
||||
@ -255,8 +232,7 @@ class ProductManager:
|
||||
'category_info': {
|
||||
'name': product_info.get('category_name'),
|
||||
'description': product_info.get('category_description')
|
||||
},
|
||||
'operator_config': operator_config
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,110 +363,6 @@ class ProductManager:
|
||||
'message': 'Product use successful'
|
||||
}
|
||||
|
||||
async def get_operator_config(self, category_id, org_id=None, user_id=None):
|
||||
"""Get operator configuration for a category within current org."""
|
||||
if not org_id:
|
||||
org_id = self._get_current_org_id()
|
||||
if not user_id:
|
||||
env = ServerEnv()
|
||||
try:
|
||||
user_id = await env.get_user()
|
||||
except:
|
||||
user_id = 'anonymous'
|
||||
|
||||
dbname = self._get_dbname()
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
sql = """SELECT * FROM product_type_config
|
||||
WHERE category_id = ${category_id}$
|
||||
AND org_id = ${org_id}$
|
||||
AND enabled_flg = '1'
|
||||
AND (operator_id = ${user_id}$ OR operator_id = '0')
|
||||
ORDER BY created_at DESC"""
|
||||
rows = await sor.sqlExe(sql, {
|
||||
'category_id': category_id,
|
||||
'org_id': org_id,
|
||||
'user_id': user_id
|
||||
})
|
||||
|
||||
configs = []
|
||||
for r in (rows or []):
|
||||
r = dict(r)
|
||||
config_json = r.get('config_json', '')
|
||||
if config_json:
|
||||
try:
|
||||
r['config_parsed'] = json.loads(config_json)
|
||||
except:
|
||||
r['config_parsed'] = {}
|
||||
configs.append(r)
|
||||
|
||||
return {'success': True, 'configs': configs}
|
||||
|
||||
async def set_operator_config(self, category_id, config_name, config_json, org_id=None, user_id=None):
|
||||
"""Create or update operator configuration within current org."""
|
||||
if not org_id:
|
||||
org_id = self._get_current_org_id()
|
||||
if not user_id:
|
||||
env = ServerEnv()
|
||||
try:
|
||||
user_id = await env.get_user()
|
||||
except:
|
||||
return {'success': False, 'message': 'User not authenticated'}
|
||||
|
||||
if not config_name:
|
||||
return {'success': False, 'message': 'Missing config_name'}
|
||||
|
||||
dbname = self._get_dbname()
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
try:
|
||||
json.loads(config_json)
|
||||
except:
|
||||
return {'success': False, 'message': 'Invalid config_json format'}
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
# Verify category belongs to org
|
||||
cat_check = await sor.sqlExe(
|
||||
"SELECT id FROM product_category WHERE id = ${category_id}$ AND org_id = ${org_id}$",
|
||||
{'category_id': category_id, 'org_id': org_id}
|
||||
)
|
||||
if not cat_check:
|
||||
return {'success': False, 'message': 'Category not found or no access'}
|
||||
|
||||
existing = await sor.sqlExe(
|
||||
"""SELECT id FROM product_type_config
|
||||
WHERE category_id = ${category_id}$
|
||||
AND org_id = ${org_id}$
|
||||
AND operator_id = ${user_id}$
|
||||
AND config_name = ${config_name}$""",
|
||||
{'category_id': category_id, 'org_id': org_id,
|
||||
'user_id': user_id, 'config_name': config_name}
|
||||
)
|
||||
|
||||
if existing:
|
||||
config_id = existing[0]['id']
|
||||
await sor.U('product_type_config', {
|
||||
'id': config_id,
|
||||
'config_json': config_json,
|
||||
'updated_at': now
|
||||
})
|
||||
return {'success': True, 'id': config_id, 'message': 'Config updated'}
|
||||
else:
|
||||
config_id = getID()
|
||||
await sor.C('product_type_config', {
|
||||
'id': config_id,
|
||||
'operator_id': user_id,
|
||||
'org_id': org_id,
|
||||
'category_id': category_id,
|
||||
'config_name': config_name,
|
||||
'config_json': config_json,
|
||||
'enabled_flg': '1',
|
||||
'created_by': user_id,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
})
|
||||
return {'success': True, 'id': config_id, 'message': 'Config created'}
|
||||
|
||||
# ─── Resource Binding ───
|
||||
|
||||
async def bind_resource(self, product_id, resource_type, resource_ref_id,
|
||||
|
||||
@ -57,15 +57,12 @@ PATHS_LOGINED = [
|
||||
# Feature pages
|
||||
f"/{MOD}/category_manage.ui",
|
||||
f"/{MOD}/product_manage.ui",
|
||||
f"/{MOD}/product_type_config_manage.ui",
|
||||
|
||||
# CRUD alias directories (directory path + index.ui path)
|
||||
f"/{MOD}/product_category_tree",
|
||||
f"/{MOD}/product_category_tree/index.ui",
|
||||
f"/{MOD}/product_list",
|
||||
f"/{MOD}/product_list/index.ui",
|
||||
f"/{MOD}/product_type_config_list",
|
||||
f"/{MOD}/product_type_config_list/index.ui",
|
||||
|
||||
# API endpoints (.dspy)
|
||||
f"/{MOD}/api/category_options.dspy",
|
||||
@ -79,9 +76,6 @@ PATHS_LOGINED = [
|
||||
f"/{MOD}/api/product_detail.dspy",
|
||||
f"/{MOD}/api/product_purchase.dspy",
|
||||
f"/{MOD}/api/product_use.dspy",
|
||||
f"/{MOD}/api/product_type_config_create.dspy",
|
||||
f"/{MOD}/api/product_type_config_update.dspy",
|
||||
f"/{MOD}/api/product_type_config_delete.dspy",
|
||||
|
||||
# CRUD auto-generated .dspy
|
||||
f"/{MOD}/product_category_tree/get_product_category.dspy",
|
||||
@ -92,10 +86,6 @@ PATHS_LOGINED = [
|
||||
f"/{MOD}/product_list/add_product.dspy",
|
||||
f"/{MOD}/product_list/update_product.dspy",
|
||||
f"/{MOD}/product_list/delete_product.dspy",
|
||||
f"/{MOD}/product_type_config_list/get_product_type_config.dspy",
|
||||
f"/{MOD}/product_type_config_list/add_product_type_config.dspy",
|
||||
f"/{MOD}/product_type_config_list/update_product_type_config.dspy",
|
||||
f"/{MOD}/product_type_config_list/delete_product_type_config.dspy",
|
||||
|
||||
# Resource binding
|
||||
f"/{MOD}/product_resource_list",
|
||||
|
||||
@ -6,11 +6,10 @@
|
||||
product_code: 产品编码 (可选)
|
||||
org_id: 机构ID (可选,不传则用当前用户机构)
|
||||
返回:
|
||||
{success, data: {product_info, category_info, operator_config, extra_parsed}}
|
||||
{success, data: {product_info, category_info, extra_parsed}}
|
||||
说明:
|
||||
product_info 包含产品全部信息
|
||||
extra_parsed 是 extra_json 解析后的结构化数据
|
||||
operator_config 是当前运营商对该产品类型的配置
|
||||
"""
|
||||
import json
|
||||
|
||||
@ -63,36 +62,12 @@ try:
|
||||
extra_parsed = {'_raw': extra_str}
|
||||
product_info['extra_parsed'] = extra_parsed
|
||||
|
||||
# Get operator config for this product_type
|
||||
config_sql = """SELECT * FROM product_type_config
|
||||
WHERE category_id = ${category_id}$
|
||||
AND enabled_flg = '1'
|
||||
AND org_id = ${org_id}$
|
||||
AND (operator_id = ${user_id}$ OR operator_id = '0')
|
||||
ORDER BY created_at DESC LIMIT 1"""
|
||||
config_rows = await sor.sqlExe(config_sql, {
|
||||
'category_id': product_info['category_id'],
|
||||
'org_id': org_id,
|
||||
'user_id': user_id
|
||||
})
|
||||
|
||||
operator_config = {}
|
||||
if config_rows:
|
||||
operator_config = dict(config_rows[0])
|
||||
config_json = operator_config.get('config_json', '')
|
||||
if config_json:
|
||||
try:
|
||||
operator_config['config_parsed'] = json.loads(config_json)
|
||||
except:
|
||||
operator_config['config_parsed'] = {}
|
||||
|
||||
result['data'] = {
|
||||
'product_info': product_info,
|
||||
'category_info': {
|
||||
'name': product_info.get('category_name'),
|
||||
'description': product_info.get('category_description')
|
||||
},
|
||||
'operator_config': operator_config
|
||||
}
|
||||
}
|
||||
result['success'] = True
|
||||
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
user_id = await get_user()
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
|
||||
dbname = get_module_dbname('product_management')
|
||||
data = dict(params_kw)
|
||||
data['id'] = getID()
|
||||
data['operator_id'] = user_id
|
||||
data['org_id'] = org_id
|
||||
data['created_by'] = user_id
|
||||
data['created_at'] = timestampstr()
|
||||
data['updated_at'] = timestampstr()
|
||||
if 'enabled_flg' not in data:
|
||||
data['enabled_flg'] = '1'
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
await sor.C('product_type_config', data)
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '配置创建成功', 'type': 'success'}}
|
||||
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': '创建失败: ' + str(e), 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
user_id = await get_user()
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
|
||||
dbname = get_module_dbname('product_management')
|
||||
data = dict(params_kw)
|
||||
record_id = data.get('id')
|
||||
if not record_id:
|
||||
raise ValueError('Missing id')
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
check = await sor.sqlExe(
|
||||
"SELECT id FROM product_type_config WHERE id = ${id}$ AND org_id = ${org_id}$",
|
||||
{'id': record_id, 'org_id': org_id}
|
||||
)
|
||||
if not check:
|
||||
raise ValueError('无权删除该记录')
|
||||
|
||||
await sor.D('product_type_config', {'id': record_id, 'org_id': org_id})
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '配置删除成功', 'type': 'success'}}
|
||||
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': '删除失败: ' + str(e), 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
@ -1,32 +0,0 @@
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid', 'type': 'error'}}
|
||||
|
||||
try:
|
||||
user_id = await get_user()
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
|
||||
dbname = get_module_dbname('product_management')
|
||||
data = dict(params_kw)
|
||||
record_id = data.pop('id', None)
|
||||
if not record_id:
|
||||
raise ValueError('Missing id')
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
check = await sor.sqlExe(
|
||||
"SELECT id FROM product_type_config WHERE id = ${id}$ AND org_id = ${org_id}$",
|
||||
{'id': record_id, 'org_id': org_id}
|
||||
)
|
||||
if not check:
|
||||
raise ValueError('无权操作该记录')
|
||||
|
||||
data['updated_at'] = timestampstr()
|
||||
data['id'] = record_id
|
||||
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
await sor.U('product_type_config', data)
|
||||
|
||||
result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '配置更新成功', 'type': 'success'}}
|
||||
|
||||
except Exception as e:
|
||||
result['options'] = {'title': 'Error', 'message': '更新失败: ' + str(e), 'type': 'error'}
|
||||
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
@ -28,7 +28,7 @@
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "产品类别、产品信息与运营商配置管理",
|
||||
"text": "产品类别与产品信息管理",
|
||||
"fontSize": "14px"
|
||||
}
|
||||
}
|
||||
@ -113,42 +113,6 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"padding": "16px 24px",
|
||||
"borderRadius": "8px",
|
||||
"cursor": "pointer"
|
||||
},
|
||||
"binds": [
|
||||
{
|
||||
"wid": "self",
|
||||
"event": "click",
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.product_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('product_type_config_list')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
],
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title5",
|
||||
"options": {
|
||||
"text": "运营商配置",
|
||||
"fontWeight": "600"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {
|
||||
"text": "配置运营商产品类型参数",
|
||||
"fontSize": "12px"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@ -11,8 +11,7 @@
|
||||
{"name": "resource", "label": "产品资源绑定", "url": "{{entire_url('/product_management/product_resource_list')}}"},
|
||||
{"name": "supplier", "label": "资源供应商关联", "url": "{{entire_url('/product_management/product_resource_supplier_list')}}"},
|
||||
{"name": "subscription", "label": "客户订购管理", "url": "{{entire_url('/product_management/product_subscription_list')}}"},
|
||||
{"name": "usage", "label": "产品消费记录", "url": "{{entire_url('/product_management/product_usage_log_list')}}"},
|
||||
{"name": "config", "label": "运营商配置", "url": "{{entire_url('/product_management/product_type_config_list')}}"}
|
||||
{"name": "usage", "label": "产品消费记录", "url": "{{entire_url('/product_management/product_usage_log_list')}}"}
|
||||
{% endif %}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
|
||||
ns = params_kw.copy()
|
||||
for k,v in ns.items():
|
||||
if v == 'NaN' or v == 'null':
|
||||
ns[k] = None
|
||||
id = params_kw.id
|
||||
if not id or len(id) > 32:
|
||||
id = uuid()
|
||||
ns['id'] = id
|
||||
|
||||
|
||||
userid = await get_user()
|
||||
if not userid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['operator_id'] = userid
|
||||
|
||||
|
||||
userorgid = await get_userorgid()
|
||||
if not userorgid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['org_id'] = userorgid
|
||||
ns['created_at'] = timestampstr()
|
||||
ns['updated_at'] = timestampstr()
|
||||
|
||||
db = DBPools()
|
||||
dbname = get_module_dbname('product_management')
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
r = await sor.C('product_type_config', ns.copy())
|
||||
return {
|
||||
"widgettype":"Message",
|
||||
"options":{
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"title":"Add Success",
|
||||
"timeout":3,
|
||||
"message":"ok"
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Add Error",
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"timeout":3,
|
||||
"message":"failed"
|
||||
}
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
|
||||
ns = {
|
||||
'id':params_kw['id'],
|
||||
}
|
||||
|
||||
userid = await get_user()
|
||||
if not userid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['operator_id'] = userid
|
||||
|
||||
|
||||
userorgid = await get_userorgid()
|
||||
if not userorgid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['org_id'] = userorgid
|
||||
|
||||
db = DBPools()
|
||||
dbname = get_module_dbname('product_management')
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
r = await sor.D('product_type_config', ns)
|
||||
debug('delete success');
|
||||
return {
|
||||
"widgettype":"Message",
|
||||
"options":{
|
||||
"title":"Delete Success",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"ok"
|
||||
}
|
||||
}
|
||||
|
||||
debug('Delete failed');
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Delete Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"failed"
|
||||
}
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
|
||||
ns = params_kw.copy()
|
||||
|
||||
userid = await get_user()
|
||||
if not userid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['operator_id'] = userid
|
||||
ns['userid'] = userid
|
||||
|
||||
|
||||
userorgid = await get_userorgid()
|
||||
if not userorgid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['org_id'] = userorgid
|
||||
ns['userorgid'] = userorgid
|
||||
|
||||
debug(f'get_product_type_config.dspy:{ns=}')
|
||||
if not ns.get('page'):
|
||||
ns['page'] = 1
|
||||
if not ns.get('sort'):
|
||||
|
||||
|
||||
ns['sort'] = ["created_at desc"]
|
||||
|
||||
|
||||
|
||||
sql = '''select a.*, b.category_id_text, c.enabled_flg_text
|
||||
from (select * from product_type_config where 1=1 [[filterstr]]) a left join (select id as category_id,
|
||||
name as category_id_text from product_category where has_product='1' AND status='1') b on a.category_id = b.category_id left join (select k as enabled_flg,
|
||||
v as enabled_flg_text from appcodes_kv where id='enabled_flg') c on a.enabled_flg = c.enabled_flg'''
|
||||
|
||||
filterjson = params_kw.get('data_filter')
|
||||
fields_str=r'''[
|
||||
{
|
||||
"name": "id",
|
||||
"title": "主键ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "operator_id",
|
||||
"title": "运营商用户ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"title": "所属机构ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "category_id",
|
||||
"title": "产品类别ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "config_name",
|
||||
"title": "配置名称",
|
||||
"type": "str",
|
||||
"length": 255,
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "config_json",
|
||||
"title": "配置内容",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "enabled_flg",
|
||||
"title": "是否启用",
|
||||
"type": "char",
|
||||
"length": 1,
|
||||
"default": "1"
|
||||
},
|
||||
{
|
||||
"name": "created_by",
|
||||
"title": "创建人",
|
||||
"type": "str",
|
||||
"length": 32
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"title": "创建时间",
|
||||
"type": "datetime",
|
||||
"nullable": "no"
|
||||
},
|
||||
{
|
||||
"name": "updated_at",
|
||||
"title": "更新时间",
|
||||
"type": "datetime",
|
||||
"nullable": "no"
|
||||
}
|
||||
]'''
|
||||
ori_fields = json.loads(fields_str)
|
||||
if not filterjson:
|
||||
fields = [ f['name'] for f in ori_fields ]
|
||||
filterjson = default_filterjson(fields, ns)
|
||||
filterdic = ns.copy()
|
||||
filterdic['filterstr'] = ''
|
||||
filterdic['userorgid'] = '${userorgid}$'
|
||||
filterdic['userid'] = '${userid}$'
|
||||
if filterjson:
|
||||
dbf = DBFilter(filterjson)
|
||||
conds = dbf.gen(ns)
|
||||
if conds:
|
||||
ns.update(dbf.consts)
|
||||
conds = f' and {conds}'
|
||||
filterdic['filterstr'] = conds
|
||||
ac = ArgsConvert('[[', ']]')
|
||||
vars = ac.findAllVariables(sql)
|
||||
NameSpace = {v:'${' + v + '}$' for v in vars if v != 'filterstr' }
|
||||
filterdic.update(NameSpace)
|
||||
sql = ac.convert(sql, filterdic)
|
||||
|
||||
debug(f'{sql=}')
|
||||
db = DBPools()
|
||||
dbname = get_module_dbname('product_management')
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
r = await sor.sqlPaging(sql, ns)
|
||||
return r
|
||||
return {
|
||||
"total":0,
|
||||
"rows":[]
|
||||
}
|
||||
@ -1,227 +0,0 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {
|
||||
"css": "filler", "height": "100%",
|
||||
"width": "100%"
|
||||
},
|
||||
"subwidgets": [
|
||||
{
|
||||
"id":"product_type_config_tbl",
|
||||
"widgettype":"Tabular",
|
||||
"options":{
|
||||
"width":"100%",
|
||||
"height":"100%",
|
||||
|
||||
|
||||
"title":"运营商产品类型配置",
|
||||
|
||||
|
||||
|
||||
|
||||
"css":"card",
|
||||
|
||||
|
||||
"editable":{
|
||||
|
||||
"new_data_url":"{{entire_url('add_product_type_config.dspy')}}",
|
||||
|
||||
|
||||
"delete_data_url":"{{entire_url('delete_product_type_config.dspy')}}",
|
||||
|
||||
|
||||
"update_data_url":"{{entire_url('update_product_type_config.dspy')}}"
|
||||
|
||||
},
|
||||
|
||||
|
||||
"data_url":"{{entire_url('./get_product_type_config.dspy')}}",
|
||||
|
||||
"data_method":"GET",
|
||||
"data_params":{{json.dumps(params_kw, indent=4, ensure_ascii=False)}},
|
||||
"row_options":{
|
||||
|
||||
|
||||
|
||||
"browserfields": {
|
||||
"exclouded": [],
|
||||
"alters": {
|
||||
"category_id": {
|
||||
"uitype": "code",
|
||||
"dataurl": "{{entire_url('../api/category_options.dspy')}}",
|
||||
"datamethod": "GET"
|
||||
},
|
||||
"enabled_flg": {
|
||||
"uitype": "code",
|
||||
"data": [
|
||||
{
|
||||
"value": "1",
|
||||
"text": "启用"
|
||||
},
|
||||
{
|
||||
"value": "0",
|
||||
"text": "禁用"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
"editexclouded":[
|
||||
"operator_id",
|
||||
"created_by",
|
||||
"created_at",
|
||||
"updated_at"
|
||||
],
|
||||
|
||||
"fields":[
|
||||
{
|
||||
"name": "id",
|
||||
"title": "主键ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"cwidth": 18,
|
||||
"uitype": "str",
|
||||
"datatype": "str",
|
||||
"label": "主键ID"
|
||||
},
|
||||
{
|
||||
"name": "operator_id",
|
||||
"title": "运营商用户ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"cwidth": 18,
|
||||
"uitype": "str",
|
||||
"datatype": "str",
|
||||
"label": "运营商用户ID"
|
||||
},
|
||||
{
|
||||
"name": "org_id",
|
||||
"title": "所属机构ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"cwidth": 18,
|
||||
"uitype": "str",
|
||||
"datatype": "str",
|
||||
"label": "所属机构ID"
|
||||
},
|
||||
{
|
||||
"name": "category_id",
|
||||
"title": "产品类别ID",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"nullable": "no",
|
||||
"label": "产品类别ID",
|
||||
"uitype": "code",
|
||||
"valueField": "category_id",
|
||||
"textField": "category_id_text",
|
||||
"params": {
|
||||
"dbname": "{{get_module_dbname('product_management')}}",
|
||||
"table": "product_category",
|
||||
"tblvalue": "id",
|
||||
"tbltext": "name",
|
||||
"valueField": "category_id",
|
||||
"textField": "category_id_text",
|
||||
"cond": "has_product='1' AND status='1'"
|
||||
},
|
||||
"dataurl": "{{entire_url('../api/category_options.dspy')}}",
|
||||
"datamethod": "GET"
|
||||
},
|
||||
{
|
||||
"name": "config_name",
|
||||
"title": "配置名称",
|
||||
"type": "str",
|
||||
"length": 255,
|
||||
"nullable": "no",
|
||||
"cwidth": 18,
|
||||
"uitype": "str",
|
||||
"datatype": "str",
|
||||
"label": "配置名称"
|
||||
},
|
||||
{
|
||||
"name": "config_json",
|
||||
"title": "配置内容",
|
||||
"type": "text",
|
||||
"length": 0,
|
||||
"uitype": "text",
|
||||
"datatype": "text",
|
||||
"label": "配置内容"
|
||||
},
|
||||
{
|
||||
"name": "enabled_flg",
|
||||
"title": "是否启用",
|
||||
"type": "char",
|
||||
"length": 1,
|
||||
"default": "1",
|
||||
"label": "是否启用",
|
||||
"uitype": "code",
|
||||
"valueField": "enabled_flg",
|
||||
"textField": "enabled_flg_text",
|
||||
"params": {
|
||||
"dbname": "{{get_module_dbname('product_management')}}",
|
||||
"table": "appcodes_kv",
|
||||
"tblvalue": "k",
|
||||
"tbltext": "v",
|
||||
"valueField": "enabled_flg",
|
||||
"textField": "enabled_flg_text",
|
||||
"cond": "id='enabled_flg'"
|
||||
},
|
||||
"dataurl": "{{entire_url('/appbase/get_code.dspy')}}",
|
||||
"data": [
|
||||
{
|
||||
"value": "1",
|
||||
"text": "启用"
|
||||
},
|
||||
{
|
||||
"value": "0",
|
||||
"text": "禁用"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "created_by",
|
||||
"title": "创建人",
|
||||
"type": "str",
|
||||
"length": 32,
|
||||
"cwidth": 18,
|
||||
"uitype": "str",
|
||||
"datatype": "str",
|
||||
"label": "创建人"
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"title": "创建时间",
|
||||
"type": "datetime",
|
||||
"nullable": "no",
|
||||
"length": 0,
|
||||
"uitype": "str",
|
||||
"datatype": "datetime",
|
||||
"label": "创建时间"
|
||||
},
|
||||
{
|
||||
"name": "updated_at",
|
||||
"title": "更新时间",
|
||||
"type": "datetime",
|
||||
"nullable": "no",
|
||||
"length": 0,
|
||||
"uitype": "str",
|
||||
"datatype": "datetime",
|
||||
"label": "更新时间"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
|
||||
"page_rows":160,
|
||||
"cache_limit":5
|
||||
}
|
||||
|
||||
,"binds":[]
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,87 +0,0 @@
|
||||
|
||||
ns = params_kw.copy()
|
||||
for k,v in ns.items():
|
||||
if v == 'NaN' or v == 'null':
|
||||
ns[k] = None
|
||||
|
||||
userid = await get_user()
|
||||
if not userid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['operator_id'] = userid
|
||||
|
||||
|
||||
userorgid = await get_userorgid()
|
||||
if not userorgid:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Authorization Error",
|
||||
"timeout":3,
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"message":"Please login"
|
||||
}
|
||||
}
|
||||
ns['org_id'] = userorgid
|
||||
ns['updated_at'] = timestampstr()
|
||||
|
||||
|
||||
|
||||
db = DBPools()
|
||||
dbname = get_module_dbname('product_management')
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
|
||||
ns1 = {
|
||||
|
||||
"org_id": userorgid,
|
||||
|
||||
|
||||
"operator_id": userid,
|
||||
|
||||
"id": params_kw.id
|
||||
}
|
||||
recs = await sor.R('product_type_config', ns1)
|
||||
if len(recs) < 1:
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Update Error",
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"timeout":3,
|
||||
"message":"Record no exist or with wrong ownership"
|
||||
}
|
||||
}
|
||||
|
||||
r = await sor.U('product_type_config', ns)
|
||||
debug('update success');
|
||||
return {
|
||||
"widgettype":"Message",
|
||||
"options":{
|
||||
"title":"Update Success",
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"timeout":3,
|
||||
"message":"ok"
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"widgettype":"Error",
|
||||
"options":{
|
||||
"title":"Update Error",
|
||||
"cwidth":16,
|
||||
"cheight":9,
|
||||
"timeout":3,
|
||||
"message":"failed"
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "16px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "运营商产品类型配置", "fontSize": "20px", "fontWeight": "bold", "marginBottom": "16px"}
|
||||
},
|
||||
{
|
||||
"widgettype": "Html",
|
||||
"options": {
|
||||
"html": "<iframe src=\"{{entire_url('/product_management/product_type_config_list')}}\" style=\"width:100%;height:calc(100vh - 200px);border:none;\"></iframe>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user