画廊添加

This commit is contained in:
2026-08-08 16:06:36 +08:00
parent 989ad91b69
commit b21043e3b8
17 changed files with 1008 additions and 170 deletions
+112 -1
View File
@@ -428,6 +428,32 @@ Json make_amis_view_node(const View_Node& node, const Json& descriptor_json, std
if(node.kind == View_Node_Kind::field) {
return make_typed_amis_control_by_name(descriptor_json, descriptor, node.field, permission, prefix);
}
if(node.kind == View_Node_Kind::frontend) {
Json result = json_object<Json>();
json_set(result, "type", "container");
json_set(result, "body", make_amis_view_body<Json, T>(View_Node{View_Node_Kind::vertical, {}, {}, {}, {}, 0, false, false, node.children}, descriptor_json, permission, prefix));
json_set(result, "className", "adminive-frontend-placement");
apply_view_node_options(result, node, prefix);
return result;
}
if(node.kind == View_Node_Kind::list) {
Json body = json_array<Json>();
for(const auto& child : node.children) {
Json item = json_object<Json>();
json_set(item, "type", "container");
json_set(item, "body", make_amis_view_body<Json, T>(child, descriptor_json, permission, prefix));
Json style = json_object<Json>();
json_set(style, "padding", "10px 0");
json_set(style, "borderBottom", "1px solid #e5e7eb");
json_set(item, "style", std::move(style));
json_append(body, std::move(item));
}
Json result = json_object<Json>();
json_set(result, "type", "container");
json_set(result, "body", std::move(body));
apply_view_node_options(result, node, prefix);
return result;
}
if(node.kind == View_Node_Kind::group) {
Json result = json_object<Json>();
json_set(result, "type", "fieldset");
@@ -571,6 +597,32 @@ Json make_amis_composition_node(const Composition_Node& node, const std::map<std
apply_composition_node_options(result, node);
return result;
}
if(node.kind == Composition_Node_Kind::frontend) {
Json result = json_object<Json>();
json_set(result, "type", "container");
json_set(result, "body", make_amis_composition_body<Json>(Composition_Node{Composition_Node_Kind::vertical, {}, {}, {}, {}, {}, 0, false, false, node.children}, slots));
json_set(result, "className", "adminive-frontend-placement");
apply_composition_node_options(result, node);
return result;
}
if(node.kind == Composition_Node_Kind::list) {
Json body = json_array<Json>();
for(const auto& child : node.children) {
Json item = json_object<Json>();
json_set(item, "type", "container");
json_set(item, "body", make_amis_composition_body<Json>(child, slots));
Json style = json_object<Json>();
json_set(style, "padding", "10px 0");
json_set(style, "borderBottom", "1px solid #e5e7eb");
json_set(item, "style", std::move(style));
json_append(body, std::move(item));
}
Json result = json_object<Json>();
json_set(result, "type", "container");
json_set(result, "body", std::move(body));
apply_composition_node_options(result, node);
return result;
}
if(node.kind == Composition_Node_Kind::group) {
Json result = json_object<Json>();
json_set(result, "type", "panel");
@@ -943,5 +995,64 @@ Json to_amis_table_schema(std::string base_api, const Table_View& view, const Js
json_set(result, "body", std::move(page_body));
return result;
}
template <Json_Type Json>
Json amis_collection_actions(const Json& crud) {
const auto& columns = Json_Adapter<Json>::at(crud, "columns");
return Json_Adapter<Json>::at(Json_Adapter<Json>::at(columns, Json_Adapter<Json>::size(columns) - 1), "buttons");
}
template <Json_Type Json>
void replace_amis_reload_target(Json& value, std::string_view old_target, std::string_view new_target) {
if(Json_Adapter<Json>::is_object(value)) {
if(Json_Adapter<Json>::contains(value, "reload")) {
auto& reload = Json_Adapter<Json>::at(value, "reload");
if(Json_Adapter<Json>::is_string(reload) && json_get<Json, std::string>(reload) == old_target) {
json_set(value, "reload", new_target);
}
}
for(const auto& key : Json_Adapter<Json>::keys(value)) {
replace_amis_reload_target<Json>(Json_Adapter<Json>::at(value, key), old_target, new_target);
}
return;
}
if(Json_Adapter<Json>::is_array(value)) {
for(std::size_t index = 0; index < Json_Adapter<Json>::size(value); ++index) {
replace_amis_reload_target<Json>(Json_Adapter<Json>::at(value, index), old_target, new_target);
}
}
}
template <Json_Type Json>
Json make_amis_collection_variant(Json schema, std::string mode, std::string item_key, Json item, std::size_t columns_count = 0) {
auto& body = Json_Adapter<Json>::at(schema, "body");
auto& crud = Json_Adapter<Json>::at(body, Json_Adapter<Json>::size(body) - 1);
const std::string old_id = json_get<Json, std::string>(Json_Adapter<Json>::at(crud, "id"));
const std::string id = old_id + "_" + mode;
if(!Json_Adapter<Json>::contains(item, "actions")) {
json_set(item, "actions", amis_collection_actions<Json>(crud));
}
const auto& old_toolbar = Json_Adapter<Json>::at(crud, "headerToolbar");
Json toolbar = json_array<Json>();
for(std::size_t index = 1; index < Json_Adapter<Json>::size(old_toolbar); ++index) {
json_append(toolbar, Json_Adapter<Json>::at(old_toolbar, index));
}
Json_Adapter<Json>::erase(crud, "columns");
json_set(crud, "id", id);
json_set(crud, "headerToolbar", std::move(toolbar));
json_set(crud, "mode", std::move(mode));
json_set(crud, item_key, std::move(item));
if(columns_count != 0) {
json_set(crud, "columnsCount", columns_count);
}
replace_amis_reload_target<Json>(crud, old_id, id);
return schema;
}
template <Json_Type Json, class T>
requires Described_Type<Object_Model_Type<T>>
Json to_amis_list_schema(std::string base_api, const Table_View& view, Json list_item, const Json* item_status_descriptor = nullptr, std::uint64_t item_status_interval = 2000, const Json* overview_status_descriptor = nullptr, std::string overview_status_api = {}, std::uint64_t overview_status_interval = 2000) {
return make_amis_collection_variant<Json>(to_amis_table_schema<Json, T>(std::move(base_api), view, item_status_descriptor, item_status_interval, overview_status_descriptor, std::move(overview_status_api), overview_status_interval), "list", "listItem", std::move(list_item));
}
template <Json_Type Json, class T>
requires Described_Type<Object_Model_Type<T>>
Json to_amis_cards_schema(std::string base_api, const Table_View& view, Json card, std::size_t columns_count = 3, const Json* item_status_descriptor = nullptr, std::uint64_t item_status_interval = 2000, const Json* overview_status_descriptor = nullptr, std::string overview_status_api = {}, std::uint64_t overview_status_interval = 2000) {
return make_amis_collection_variant<Json>(to_amis_table_schema<Json, T>(std::move(base_api), view, item_status_descriptor, item_status_interval, overview_status_descriptor, std::move(overview_status_api), overview_status_interval), "cards", "card", std::move(card), columns_count);
}
}
@@ -8,10 +8,12 @@ namespace adminive {
enum class Composition_Node_Kind {
slot,
heading,
frontend,
vertical,
horizontal,
flow,
grid,
list,
group,
card,
tabs,
@@ -77,6 +79,10 @@ Composition_Node make_container(Composition_Node_Kind kind, Children&&... childr
return result;
}
template <class... Children>
Composition_Node frontend(Children&&... children) {
return make_container(Composition_Node_Kind::frontend, std::forward<Children>(children)...);
}
template <class... Children>
Composition_Node vertical(Children&&... children) {
return make_container(Composition_Node_Kind::vertical, std::forward<Children>(children)...);
}
@@ -95,6 +101,10 @@ Composition_Node grid(std::size_t columns, Children&&... children) {
return result;
}
template <class... Children>
Composition_Node list(Children&&... children) {
return make_container(Composition_Node_Kind::list, std::forward<Children>(children)...);
}
template <class... Children>
Composition_Node group(std::string title, Children&&... children) {
auto result = make_container(Composition_Node_Kind::group, std::forward<Children>(children)...);
result.title = std::move(title);
@@ -130,13 +140,16 @@ struct Composition_View {
inline Composition_View composition_view(std::string name, Composition_Node body) {
return Composition_View{std::move(name), {}, std::move(body)};
}
inline void validate_composition_node(const Composition_Node& node) {
inline void validate_composition_node_impl(const Composition_Node& node, bool tab_allowed) {
if(node.kind == Composition_Node_Kind::slot && node.slot.empty()) {
throw std::invalid_argument("composition slot name must not be empty");
}
if(node.kind == Composition_Node_Kind::grid && node.columns == 0) {
throw std::invalid_argument("composition grid requires at least one column");
}
if(node.kind == Composition_Node_Kind::tab && !tab_allowed) {
throw std::invalid_argument("composition tab can only be used inside tabs");
}
if(node.kind == Composition_Node_Kind::tabs) {
for(const auto& child : node.children) {
if(child.kind != Composition_Node_Kind::tab) {
@@ -145,9 +158,12 @@ inline void validate_composition_node(const Composition_Node& node) {
}
}
for(const auto& child : node.children) {
validate_composition_node(child);
validate_composition_node_impl(child, node.kind == Composition_Node_Kind::tabs);
}
}
inline void validate_composition_node(const Composition_Node& node) {
validate_composition_node_impl(node, false);
}
inline void validate_composition_view(const Composition_View& view) {
if(view.name.empty()) {
throw std::invalid_argument("composition view name must not be empty");
+19 -2
View File
@@ -12,10 +12,12 @@ namespace adminive {
enum class View_Node_Kind {
all_fields,
field,
frontend,
vertical,
horizontal,
flow,
grid,
list,
group,
card,
tabs,
@@ -107,6 +109,10 @@ View_Node make_view_container(View_Node_Kind kind, Children&&... children) {
return result;
}
template <class... Children>
View_Node frontend(Children&&... children) {
return make_view_container(View_Node_Kind::frontend, std::forward<Children>(children)...);
}
template <class... Children>
View_Node vertical(Children&&... children) {
return make_view_container(View_Node_Kind::vertical, std::forward<Children>(children)...);
}
@@ -125,6 +131,10 @@ View_Node grid(std::size_t columns, Children&&... children) {
return result;
}
template <class... Children>
View_Node list(Children&&... children) {
return make_view_container(View_Node_Kind::list, std::forward<Children>(children)...);
}
template <class... Children>
View_Node group(std::string title, Children&&... children) {
auto result = make_view_container(View_Node_Kind::group, std::forward<Children>(children)...);
result.title = std::move(title);
@@ -380,7 +390,7 @@ bool descriptor_has_field(const Descriptor& descriptor, std::string_view name) {
return found;
}
template <Described_Type T>
void validate_view_node(const View_Node& node) {
void validate_view_node_impl(const View_Node& node, bool tab_allowed) {
const auto descriptor = describe<T>();
if(node.kind == View_Node_Kind::field && !descriptor_has_field(descriptor, node.field)) {
throw std::invalid_argument("view field does not exist: " + node.field);
@@ -388,6 +398,9 @@ void validate_view_node(const View_Node& node) {
if(node.kind == View_Node_Kind::grid && node.columns == 0) {
throw std::invalid_argument("grid view requires at least one column");
}
if(node.kind == View_Node_Kind::tab && !tab_allowed) {
throw std::invalid_argument("tab view can only be used inside tabs");
}
if(node.kind == View_Node_Kind::tabs) {
for(const auto& child : node.children) {
if(child.kind != View_Node_Kind::tab) {
@@ -396,10 +409,14 @@ void validate_view_node(const View_Node& node) {
}
}
for(const auto& child : node.children) {
validate_view_node<T>(child);
validate_view_node_impl<T>(child, node.kind == View_Node_Kind::tabs);
}
}
template <Described_Type T>
void validate_view_node(const View_Node& node) {
validate_view_node_impl<T>(node, false);
}
template <Described_Type T>
void validate_form_view(const Form_View& view) {
if(view.name.empty()) {
throw std::invalid_argument("form view name must not be empty");
@@ -9,6 +9,8 @@ inline std::string_view composition_node_kind_name(Composition_Node_Kind value)
return "slot";
case Composition_Node_Kind::heading:
return "heading";
case Composition_Node_Kind::frontend:
return "frontend";
case Composition_Node_Kind::vertical:
return "vertical";
case Composition_Node_Kind::horizontal:
@@ -17,6 +19,8 @@ inline std::string_view composition_node_kind_name(Composition_Node_Kind value)
return "flow";
case Composition_Node_Kind::grid:
return "grid";
case Composition_Node_Kind::list:
return "list";
case Composition_Node_Kind::group:
return "group";
case Composition_Node_Kind::card:
@@ -83,6 +87,8 @@ inline std::string_view view_node_kind_name(View_Node_Kind value) noexcept {
return "all_fields";
case View_Node_Kind::field:
return "field";
case View_Node_Kind::frontend:
return "frontend";
case View_Node_Kind::vertical:
return "vertical";
case View_Node_Kind::horizontal:
@@ -91,6 +97,8 @@ inline std::string_view view_node_kind_name(View_Node_Kind value) noexcept {
return "flow";
case View_Node_Kind::grid:
return "grid";
case View_Node_Kind::list:
return "list";
case View_Node_Kind::group:
return "group";
case View_Node_Kind::card: