Ajustesgis parte 1
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
using System.IO;
|
||||
using SIG.Web.AppCode.Models.Fraccionamientos;
|
||||
|
||||
namespace SIG.Web.AppCode.Contracts.Fraccionamientos
|
||||
{
|
||||
public interface IFraccionamientoGisFileStore
|
||||
{
|
||||
string GetPhysicalPath(FraccionamientoGisContextModel context);
|
||||
bool Exists(FraccionamientoGisContextModel context);
|
||||
void Save(FraccionamientoGisContextModel context, Stream source);
|
||||
Stream OpenRead(FraccionamientoGisContextModel context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using SIG.Web.AppCode.Models.Common;
|
||||
using SIG.Web.AppCode.Models.Fraccionamientos;
|
||||
|
||||
namespace SIG.Web.AppCode.Contracts.Fraccionamientos
|
||||
{
|
||||
public interface IFraccionamientoGisRepository
|
||||
{
|
||||
DbResult<FraccionamientoGisContextModel> GetContext(
|
||||
int stageId,
|
||||
int executingUser,
|
||||
string domainName);
|
||||
|
||||
DbResult<List<FraccionamientoGisLotLinkModel>> ListLinks(
|
||||
int stageId,
|
||||
int executingUser,
|
||||
string domainName);
|
||||
|
||||
DbResult<bool> SaveLinks(
|
||||
int stageId,
|
||||
IList<FraccionamientoGisLotLinkModel> links,
|
||||
int executingUser,
|
||||
string domainName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace SIG.Web.AppCode.Models.Fraccionamientos
|
||||
{
|
||||
public sealed class FraccionamientoGisContextModel
|
||||
{
|
||||
public int CveCliente { get; set; }
|
||||
public int CveFraccionamiento { get; set; }
|
||||
public int CveFraccionamientoEtapa { get; set; }
|
||||
public string Fraccionamiento { get; set; }
|
||||
public string Etapa { get; set; }
|
||||
}
|
||||
|
||||
public sealed class FraccionamientoGisLotLinkModel
|
||||
{
|
||||
public int CveFraccionamientoLote { get; set; }
|
||||
public string Nombre { get; set; }
|
||||
public string GISPoligonoClave { get; set; }
|
||||
public bool EsActivo { get; set; }
|
||||
}
|
||||
}
|
||||
139
SIG.Web/App_Code/Repositories/Database/RepositoryBase.cs
Normal file
139
SIG.Web/App_Code/Repositories/Database/RepositoryBase.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using SIG.Web.AppCode.Contracts.Database;
|
||||
using SIG.Web.AppCode.Models.Common;
|
||||
using SIG.Web.AppCode.Utilities;
|
||||
|
||||
namespace SIG.Web.AppCode.Repositories.Database
|
||||
{
|
||||
public abstract class RepositoryBase
|
||||
{
|
||||
private readonly IDbExecutor _db;
|
||||
|
||||
protected RepositoryBase(IDbExecutor db)
|
||||
{
|
||||
if (db == null)
|
||||
{
|
||||
throw new ArgumentNullException("db");
|
||||
}
|
||||
|
||||
_db = db;
|
||||
}
|
||||
|
||||
protected DbResult<List<T>> QueryList<T>(
|
||||
string procedure,
|
||||
int user,
|
||||
string domain,
|
||||
Action<IDbCommand> parameters)
|
||||
where T : class, new()
|
||||
{
|
||||
return _db.Execute(domain, connection =>
|
||||
{
|
||||
using (IDbCommand command = connection.CreateCommand())
|
||||
{
|
||||
StoredProcedureCommand.Configure(command, procedure, user);
|
||||
|
||||
if (parameters != null)
|
||||
{
|
||||
parameters(command);
|
||||
}
|
||||
|
||||
List<T> value;
|
||||
using (IDataReader reader = command.ExecuteReader())
|
||||
{
|
||||
value = reader.ToList<T>();
|
||||
}
|
||||
|
||||
StoredProcedureCommand.EnsureSuccess(command);
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected DbResult<T> QueryOne<T>(
|
||||
string procedure,
|
||||
int user,
|
||||
string domain,
|
||||
Action<IDbCommand> parameters)
|
||||
where T : class, new()
|
||||
{
|
||||
return _db.Execute(domain, connection =>
|
||||
{
|
||||
using (IDbCommand command = connection.CreateCommand())
|
||||
{
|
||||
StoredProcedureCommand.Configure(command, procedure, user);
|
||||
|
||||
if (parameters != null)
|
||||
{
|
||||
parameters(command);
|
||||
}
|
||||
|
||||
T value;
|
||||
using (IDataReader reader = command.ExecuteReader())
|
||||
{
|
||||
value = reader.ToObject<T>();
|
||||
}
|
||||
|
||||
StoredProcedureCommand.EnsureSuccess(command);
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected DbResult<int> QueryScalarId(
|
||||
string procedure,
|
||||
int user,
|
||||
string domain,
|
||||
Action<IDbCommand> parameters)
|
||||
{
|
||||
return _db.Execute(domain, connection =>
|
||||
{
|
||||
using (IDbCommand command = connection.CreateCommand())
|
||||
{
|
||||
StoredProcedureCommand.Configure(command, procedure, user);
|
||||
|
||||
if (parameters != null)
|
||||
{
|
||||
parameters(command);
|
||||
}
|
||||
|
||||
int value;
|
||||
using (IDataReader reader = command.ExecuteReader())
|
||||
{
|
||||
value = reader.Read()
|
||||
? Convert.ToInt32(reader.GetValue(0))
|
||||
: 0;
|
||||
}
|
||||
|
||||
StoredProcedureCommand.EnsureSuccess(command);
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected DbResult<bool> Execute(
|
||||
string procedure,
|
||||
int user,
|
||||
string domain,
|
||||
Action<IDbCommand> parameters)
|
||||
{
|
||||
return _db.Execute(domain, connection =>
|
||||
{
|
||||
using (IDbCommand command = connection.CreateCommand())
|
||||
{
|
||||
StoredProcedureCommand.Configure(command, procedure, user);
|
||||
|
||||
if (parameters != null)
|
||||
{
|
||||
parameters(command);
|
||||
}
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
StoredProcedureCommand.EnsureSuccess(command);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using SIG.Web.AppCode.Contracts.Database;
|
||||
using SIG.Web.AppCode.Contracts.Fraccionamientos;
|
||||
using SIG.Web.AppCode.Models.Common;
|
||||
using SIG.Web.AppCode.Models.Fraccionamientos;
|
||||
using SIG.Web.AppCode.Repositories.Database;
|
||||
|
||||
namespace SIG.Web.AppCode.Repositories.Fraccionamientos
|
||||
{
|
||||
public sealed class FraccionamientoGisRepository
|
||||
: RepositoryBase, IFraccionamientoGisRepository
|
||||
{
|
||||
public FraccionamientoGisRepository(IDbExecutor db)
|
||||
: base(db)
|
||||
{
|
||||
}
|
||||
|
||||
public DbResult<FraccionamientoGisContextModel> GetContext(
|
||||
int stageId,
|
||||
int executingUser,
|
||||
string domainName)
|
||||
{
|
||||
return QueryOne<FraccionamientoGisContextModel>(
|
||||
"dbo.PA_Fraccionamientos_EtapaGISContextGet",
|
||||
executingUser,
|
||||
domainName,
|
||||
command => StoredProcedureCommand.AddInput(
|
||||
command,
|
||||
"@CveFraccionamientoEtapa",
|
||||
stageId,
|
||||
DbType.Int32));
|
||||
}
|
||||
|
||||
public DbResult<List<FraccionamientoGisLotLinkModel>> ListLinks(
|
||||
int stageId,
|
||||
int executingUser,
|
||||
string domainName)
|
||||
{
|
||||
return QueryList<FraccionamientoGisLotLinkModel>(
|
||||
"dbo.PA_Fraccionamientos_EtapaGISVinculosGet",
|
||||
executingUser,
|
||||
domainName,
|
||||
command => StoredProcedureCommand.AddInput(
|
||||
command,
|
||||
"@CveFraccionamientoEtapa",
|
||||
stageId,
|
||||
DbType.Int32));
|
||||
}
|
||||
|
||||
public DbResult<bool> SaveLinks(
|
||||
int stageId,
|
||||
IList<FraccionamientoGisLotLinkModel> links,
|
||||
int executingUser,
|
||||
string domainName)
|
||||
{
|
||||
IList<FraccionamientoGisLotLinkModel> safeLinks =
|
||||
links ?? new List<FraccionamientoGisLotLinkModel>();
|
||||
|
||||
XElement linksXml = new XElement(
|
||||
"Vinculos",
|
||||
safeLinks.Select(link =>
|
||||
new XElement(
|
||||
"Vinculo",
|
||||
new XAttribute(
|
||||
"CveFraccionamientoLote",
|
||||
link.CveFraccionamientoLote),
|
||||
new XAttribute(
|
||||
"GISPoligonoClave",
|
||||
link.GISPoligonoClave ?? string.Empty))));
|
||||
|
||||
return Execute(
|
||||
"dbo.PA_Fraccionamientos_EtapaGISVinculosSave",
|
||||
executingUser,
|
||||
domainName,
|
||||
command =>
|
||||
{
|
||||
StoredProcedureCommand.AddInput(
|
||||
command,
|
||||
"@CveFraccionamientoEtapa",
|
||||
stageId,
|
||||
DbType.Int32);
|
||||
StoredProcedureCommand.AddInput(
|
||||
command,
|
||||
"@VinculosXml",
|
||||
linksXml.ToString(SaveOptions.DisableFormatting),
|
||||
DbType.Xml);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Web.Hosting;
|
||||
using SIG.Web.AppCode.Contracts.Fraccionamientos;
|
||||
using SIG.Web.AppCode.Models.Fraccionamientos;
|
||||
|
||||
namespace SIG.Web.AppCode.Services.Fraccionamientos
|
||||
{
|
||||
public sealed class FraccionamientoGisFileStore : IFraccionamientoGisFileStore
|
||||
{
|
||||
public string GetPhysicalPath(FraccionamientoGisContextModel context)
|
||||
{
|
||||
ValidateContext(context);
|
||||
|
||||
string relativeDirectory = string.Format(
|
||||
"~/Documentos/Clientes/{0}/",
|
||||
context.CveCliente);
|
||||
|
||||
string directory = HostingEnvironment.MapPath(relativeDirectory);
|
||||
if (string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"No fue posible resolver el directorio de documentos GIS.");
|
||||
}
|
||||
|
||||
return Path.Combine(
|
||||
directory,
|
||||
string.Format(
|
||||
"gis-{0}-{1}.gis",
|
||||
context.CveFraccionamiento,
|
||||
context.CveFraccionamientoEtapa));
|
||||
}
|
||||
|
||||
public bool Exists(FraccionamientoGisContextModel context)
|
||||
{
|
||||
return File.Exists(GetPhysicalPath(context));
|
||||
}
|
||||
|
||||
public void Save(FraccionamientoGisContextModel context, Stream source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
string path = GetPhysicalPath(context);
|
||||
string directory = Path.GetDirectoryName(path);
|
||||
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
using (FileStream destination = new FileStream(
|
||||
path,
|
||||
FileMode.Create,
|
||||
FileAccess.Write,
|
||||
FileShare.None))
|
||||
{
|
||||
source.CopyTo(destination);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream OpenRead(FraccionamientoGisContextModel context)
|
||||
{
|
||||
return new FileStream(
|
||||
GetPhysicalPath(context),
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read);
|
||||
}
|
||||
|
||||
private static void ValidateContext(FraccionamientoGisContextModel context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException("context");
|
||||
}
|
||||
|
||||
if (context.CveCliente <= 0 ||
|
||||
context.CveFraccionamiento <= 0 ||
|
||||
context.CveFraccionamientoEtapa <= 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"El contexto del archivo GIS no contiene claves válidas.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
576
SIG.Web/Scripts/fraccionamiento-gis.js
Normal file
576
SIG.Web/Scripts/fraccionamiento-gis.js
Normal file
@@ -0,0 +1,576 @@
|
||||
(function (window, $, undefined) {
|
||||
'use strict';
|
||||
|
||||
var api = window.FraccionamientoGIS = window.FraccionamientoGIS || {};
|
||||
var current = null;
|
||||
|
||||
function normalizeOptions(options) {
|
||||
return $.extend({
|
||||
fileInputId: 'TxtGIS',
|
||||
mapId: 'MapGIS',
|
||||
linksTableId: 'GisVinculos',
|
||||
saveButtonId: 'BtnGuardarGIS',
|
||||
developmentId: 0,
|
||||
stageId: 0,
|
||||
saveUrl: '/Ashx/FraccionamientoGis.ashx',
|
||||
getUrl: '/Ashx/FraccionamientoGis.ashx',
|
||||
lots: [],
|
||||
existingLinks: [],
|
||||
initialZoom: 16,
|
||||
center: { lat: 29.072967, lng: -110.955919 }
|
||||
}, options || {});
|
||||
}
|
||||
|
||||
function createState(options) {
|
||||
var state = {
|
||||
options: normalizeOptions(options),
|
||||
map: null,
|
||||
data: null,
|
||||
geojson: null,
|
||||
file: null,
|
||||
polygonKeys: [],
|
||||
polygonNameByKey: {},
|
||||
linksByPolygonKey: {},
|
||||
polygonByLotId: {},
|
||||
lotsById: {}
|
||||
};
|
||||
|
||||
$.each(state.options.lots || [], function (_, lot) {
|
||||
var id = parseInt(lot.CveFraccionamientoLote || lot.cveFraccionamientoLote, 10);
|
||||
if (id > 0) {
|
||||
state.lotsById[id] = lot;
|
||||
}
|
||||
});
|
||||
|
||||
$.each(state.options.existingLinks || [], function (_, link) {
|
||||
var key = link.GISPoligonoClave || link.gisPoligonoClave;
|
||||
var lotId = parseInt(link.CveFraccionamientoLote || link.cveFraccionamientoLote, 10);
|
||||
if (key && lotId > 0) {
|
||||
state.linksByPolygonKey[key] = lotId;
|
||||
state.polygonByLotId[lotId] = key;
|
||||
}
|
||||
});
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function fnv1a(text) {
|
||||
var hash = 0x811c9dc5;
|
||||
var index;
|
||||
|
||||
for (index = 0; index < text.length; index++) {
|
||||
hash ^= text.charCodeAt(index);
|
||||
hash += (hash << 1) + (hash << 4) +
|
||||
(hash << 7) + (hash << 8) + (hash << 24);
|
||||
}
|
||||
|
||||
return ('00000000' + (hash >>> 0).toString(16)).slice(-8);
|
||||
}
|
||||
|
||||
function polygonKey(feature) {
|
||||
if (feature.id !== undefined && feature.id !== null && String(feature.id).trim() !== '') {
|
||||
return 'id:' + String(feature.id).trim();
|
||||
}
|
||||
|
||||
return 'geom:' + fnv1a(JSON.stringify(feature.geometry || {}));
|
||||
}
|
||||
|
||||
function validateGeoJson(value) {
|
||||
if (!value || value.type !== 'FeatureCollection' || !$.isArray(value.features)) {
|
||||
throw new Error('El archivo .gis debe contener un GeoJSON FeatureCollection válido.');
|
||||
}
|
||||
|
||||
if (value.features.length === 0) {
|
||||
throw new Error('El archivo .gis no contiene polígonos.');
|
||||
}
|
||||
|
||||
var keys = {};
|
||||
var polygons = 0;
|
||||
|
||||
$.each(value.features, function (_, feature) {
|
||||
if (!feature || !feature.geometry) {
|
||||
return;
|
||||
}
|
||||
|
||||
var geometryType = feature.geometry.type;
|
||||
if (geometryType !== 'Polygon' && geometryType !== 'MultiPolygon') {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = polygonKey(feature);
|
||||
if (keys[key]) {
|
||||
throw new Error('El archivo contiene dos polígonos con la misma clave GIS.');
|
||||
}
|
||||
|
||||
keys[key] = true;
|
||||
feature.properties = feature.properties || {};
|
||||
feature.properties._sigPolygonKey = key;
|
||||
polygons++;
|
||||
});
|
||||
|
||||
if (polygons === 0) {
|
||||
throw new Error('El archivo .gis no contiene geometrías Polygon o MultiPolygon.');
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function ensureGoogleMaps() {
|
||||
if (!window.google || !google.maps || !google.maps.Data) {
|
||||
throw new Error('Google Maps no está disponible en la página.');
|
||||
}
|
||||
}
|
||||
|
||||
function initMap(state) {
|
||||
ensureGoogleMaps();
|
||||
|
||||
var element = document.getElementById(state.options.mapId);
|
||||
if (!element) {
|
||||
throw new Error('No se encontró el contenedor del mapa GIS.');
|
||||
}
|
||||
|
||||
state.map = new google.maps.Map(element, {
|
||||
center: state.options.center,
|
||||
zoom: state.options.initialZoom,
|
||||
mapTypeId: 'roadmap'
|
||||
});
|
||||
|
||||
state.data = new google.maps.Data({ map: state.map });
|
||||
state.data.setStyle(function (feature) {
|
||||
var key = feature.getProperty('_sigPolygonKey');
|
||||
var linked = !!state.linksByPolygonKey[key];
|
||||
|
||||
return {
|
||||
fillOpacity: linked ? 0.38 : 0.18,
|
||||
strokeWeight: linked ? 3 : 2,
|
||||
clickable: true
|
||||
};
|
||||
});
|
||||
|
||||
state.data.addListener('click', function (event) {
|
||||
var key = event.feature.getProperty('_sigPolygonKey');
|
||||
openAssignModal(state, key);
|
||||
});
|
||||
}
|
||||
|
||||
function clearMap(state) {
|
||||
if (!state.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.data.forEach(function (feature) {
|
||||
state.data.remove(feature);
|
||||
});
|
||||
|
||||
state.polygonKeys = [];
|
||||
state.polygonNameByKey = {};
|
||||
}
|
||||
|
||||
function loadGeoJson(state, value) {
|
||||
value = validateGeoJson(value);
|
||||
clearMap(state);
|
||||
state.geojson = value;
|
||||
|
||||
$.each(value.features, function (_, feature) {
|
||||
if (!feature || !feature.geometry ||
|
||||
(feature.geometry.type !== 'Polygon' && feature.geometry.type !== 'MultiPolygon')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = feature.properties._sigPolygonKey;
|
||||
var name = feature.properties.Nombre ||
|
||||
feature.properties.nombre ||
|
||||
key;
|
||||
|
||||
state.polygonKeys.push(key);
|
||||
state.polygonNameByKey[key] = name;
|
||||
});
|
||||
|
||||
state.data.addGeoJson(value);
|
||||
removeLinksNotInFile(state);
|
||||
fitMap(state);
|
||||
renderLinks(state);
|
||||
state.data.setStyle(state.data.getStyle());
|
||||
}
|
||||
|
||||
function removeLinksNotInFile(state) {
|
||||
var valid = {};
|
||||
$.each(state.polygonKeys, function (_, key) {
|
||||
valid[key] = true;
|
||||
});
|
||||
|
||||
$.each($.extend({}, state.linksByPolygonKey), function (key, lotId) {
|
||||
if (!valid[key]) {
|
||||
delete state.linksByPolygonKey[key];
|
||||
delete state.polygonByLotId[lotId];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fitMap(state) {
|
||||
var bounds = new google.maps.LatLngBounds();
|
||||
var hasPoint = false;
|
||||
|
||||
state.data.forEach(function (feature) {
|
||||
feature.getGeometry().forEachLatLng(function (latLng) {
|
||||
bounds.extend(latLng);
|
||||
hasPoint = true;
|
||||
});
|
||||
});
|
||||
|
||||
if (hasPoint) {
|
||||
state.map.fitBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
function lotName(state, lotId) {
|
||||
var lot = state.lotsById[lotId];
|
||||
if (!lot) {
|
||||
return 'Lote ' + lotId;
|
||||
}
|
||||
|
||||
return lot.Nombre || lot.nombre || ('Lote ' + lotId);
|
||||
}
|
||||
|
||||
function openAssignModal(state, polygonKeyValue) {
|
||||
var modalId = 'SigGisAssignModal';
|
||||
var $modal = $('#' + modalId);
|
||||
|
||||
if ($modal.length === 0) {
|
||||
$modal = $(
|
||||
'<div class="modal fade" id="' + modalId + '" tabindex="-1" role="dialog">' +
|
||||
'<div class="modal-dialog" role="document">' +
|
||||
'<div class="modal-content">' +
|
||||
'<div class="modal-header">' +
|
||||
'<button type="button" class="close" data-dismiss="modal" aria-label="Cerrar"><span aria-hidden="true">×</span></button>' +
|
||||
'<h4 class="modal-title">Vincular polígono con lote</h4>' +
|
||||
'</div>' +
|
||||
'<div class="modal-body">' +
|
||||
'<div class="form-group">' +
|
||||
'<label>Polígono</label>' +
|
||||
'<p class="form-control-static" data-sig-gis-polygon-name></p>' +
|
||||
'</div>' +
|
||||
'<div class="form-group">' +
|
||||
'<label for="SigGisAssignLot">Lote</label>' +
|
||||
'<select id="SigGisAssignLot" class="form-control"></select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="modal-footer">' +
|
||||
'<button type="button" class="btn btn-default" data-dismiss="modal">Cancelar</button>' +
|
||||
'<button type="button" class="btn btn-danger" data-sig-gis-unlink>Quitar vínculo</button>' +
|
||||
'<button type="button" class="btn btn-primary" data-sig-gis-assign>Vincular</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>');
|
||||
$('body').append($modal);
|
||||
}
|
||||
|
||||
var currentLotId = state.linksByPolygonKey[polygonKeyValue] || 0;
|
||||
var $select = $modal.find('#SigGisAssignLot').empty();
|
||||
$select.append($('<option></option>').val('').text('Seleccione un lote'));
|
||||
|
||||
$.each(state.lotsById, function (lotIdText, lot) {
|
||||
var lotId = parseInt(lotIdText, 10);
|
||||
var assignedPolygon = state.polygonByLotId[lotId];
|
||||
|
||||
if (assignedPolygon && assignedPolygon !== polygonKeyValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
$select.append(
|
||||
$('<option></option>')
|
||||
.val(lotId)
|
||||
.text(lotName(state, lotId))
|
||||
);
|
||||
});
|
||||
|
||||
if (currentLotId) {
|
||||
$select.val(String(currentLotId));
|
||||
}
|
||||
|
||||
$modal.find('[data-sig-gis-polygon-name]').text(
|
||||
state.polygonNameByKey[polygonKeyValue] || polygonKeyValue
|
||||
);
|
||||
|
||||
$modal.off('.sigGisAssign');
|
||||
$modal.on('click.sigGisAssign', '[data-sig-gis-assign]', function () {
|
||||
var lotId = parseInt($select.val(), 10);
|
||||
if (!lotId) {
|
||||
showMessage('Seleccione un lote antes de vincular.', true);
|
||||
return;
|
||||
}
|
||||
|
||||
assign(state, polygonKeyValue, lotId);
|
||||
$modal.modal('hide');
|
||||
});
|
||||
|
||||
$modal.on('click.sigGisAssign', '[data-sig-gis-unlink]', function () {
|
||||
unlink(state, polygonKeyValue);
|
||||
$modal.modal('hide');
|
||||
});
|
||||
|
||||
$modal.modal('show');
|
||||
}
|
||||
|
||||
function assign(state, polygonKeyValue, lotId) {
|
||||
var priorLot = state.linksByPolygonKey[polygonKeyValue];
|
||||
if (priorLot) {
|
||||
delete state.polygonByLotId[priorLot];
|
||||
}
|
||||
|
||||
var priorPolygon = state.polygonByLotId[lotId];
|
||||
if (priorPolygon && priorPolygon !== polygonKeyValue) {
|
||||
delete state.linksByPolygonKey[priorPolygon];
|
||||
}
|
||||
|
||||
state.linksByPolygonKey[polygonKeyValue] = lotId;
|
||||
state.polygonByLotId[lotId] = polygonKeyValue;
|
||||
state.data.revertStyle();
|
||||
renderLinks(state);
|
||||
}
|
||||
|
||||
function unlink(state, polygonKeyValue) {
|
||||
var lotId = state.linksByPolygonKey[polygonKeyValue];
|
||||
if (lotId) {
|
||||
delete state.polygonByLotId[lotId];
|
||||
}
|
||||
|
||||
delete state.linksByPolygonKey[polygonKeyValue];
|
||||
state.data.revertStyle();
|
||||
renderLinks(state);
|
||||
}
|
||||
|
||||
function renderLinks(state) {
|
||||
var $target = $('#' + state.options.linksTableId);
|
||||
if ($target.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $table = $('<table class="table table-striped table-hover Widthall"></table>');
|
||||
var $body = $('<tbody></tbody>');
|
||||
$table.append(
|
||||
'<thead><tr><th>Polígono GIS</th><th>Lote vinculado</th><th>Estado</th></tr></thead>'
|
||||
);
|
||||
|
||||
$.each(state.polygonKeys, function (_, key) {
|
||||
var lotId = state.linksByPolygonKey[key] || 0;
|
||||
var $row = $('<tr></tr>');
|
||||
|
||||
$('<td></td>').text(state.polygonNameByKey[key] || key).appendTo($row);
|
||||
$('<td></td>').text(lotId ? lotName(state, lotId) : 'Sin vincular').appendTo($row);
|
||||
$('<td></td>').text(lotId ? 'Vinculado' : 'Pendiente').appendTo($row);
|
||||
$body.append($row);
|
||||
});
|
||||
|
||||
$table.append($body);
|
||||
$target.empty().append($table);
|
||||
}
|
||||
|
||||
function collectLinks(state) {
|
||||
var links = [];
|
||||
$.each(state.polygonKeys, function (_, key) {
|
||||
var lotId = state.linksByPolygonKey[key];
|
||||
if (lotId) {
|
||||
links.push({
|
||||
CveFraccionamientoLote: lotId,
|
||||
GISPoligonoClave: key
|
||||
});
|
||||
}
|
||||
});
|
||||
return links;
|
||||
}
|
||||
|
||||
function validateBeforeSave(state) {
|
||||
if (!state.geojson) {
|
||||
return 'Seleccione un archivo .gis válido.';
|
||||
}
|
||||
|
||||
var links = collectLinks(state);
|
||||
if (links.length !== state.polygonKeys.length) {
|
||||
return 'Debe vincular cada polígono del archivo GIS con un lote antes de guardar.';
|
||||
}
|
||||
|
||||
if (state.polygonKeys.length === 0) {
|
||||
return 'El archivo GIS no contiene polígonos para guardar.';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function save(state) {
|
||||
var validation = validateBeforeSave(state);
|
||||
if (validation) {
|
||||
showMessage(validation, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var form = new FormData();
|
||||
form.append('metodo', 'Save');
|
||||
form.append('cveFraccionamiento', state.options.developmentId);
|
||||
form.append('cveFraccionamientoEtapa', state.options.stageId);
|
||||
form.append('vinculos', JSON.stringify(collectLinks(state)));
|
||||
|
||||
if (state.file) {
|
||||
form.append('archivo', state.file, state.file.name);
|
||||
}
|
||||
|
||||
var $button = $('#' + state.options.saveButtonId);
|
||||
$button.prop('disabled', true);
|
||||
|
||||
$.ajax({
|
||||
url: state.options.saveUrl,
|
||||
type: 'POST',
|
||||
data: form,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
if (!response || response.success !== true) {
|
||||
showServerError(response);
|
||||
return;
|
||||
}
|
||||
|
||||
showMessage(response.message || 'El archivo GIS y sus vínculos se guardaron correctamente.', false);
|
||||
$(document).trigger('siggis:saved', [response]);
|
||||
}).fail(function (xhr) {
|
||||
var response = null;
|
||||
try {
|
||||
response = xhr.responseJSON || JSON.parse(xhr.responseText);
|
||||
} catch (_) {
|
||||
response = null;
|
||||
}
|
||||
showServerError(response);
|
||||
}).always(function () {
|
||||
$button.prop('disabled', false);
|
||||
});
|
||||
}
|
||||
|
||||
function showServerError(response) {
|
||||
var message = response && response.message
|
||||
? response.message
|
||||
: 'No fue posible guardar la información GIS.';
|
||||
var code = response && response.codigo
|
||||
? response.codigo
|
||||
: 'SIG-GIS';
|
||||
|
||||
if (window.SIGErrorUI && typeof window.SIGErrorUI.mostrar === 'function') {
|
||||
window.SIGErrorUI.mostrar(code, message);
|
||||
} else {
|
||||
showMessage(message + (code ? ' Código: ' + code : ''), true);
|
||||
}
|
||||
}
|
||||
|
||||
function showMessage(message, isError) {
|
||||
if (window.bootbox && typeof window.bootbox.alert === 'function') {
|
||||
window.bootbox.alert(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.console && isError) {
|
||||
console.warn(message);
|
||||
}
|
||||
window.alert(message);
|
||||
}
|
||||
|
||||
function bindFile(state) {
|
||||
var $input = $('#' + state.options.fileInputId);
|
||||
if ($input.length === 0) {
|
||||
throw new Error('No se encontró el control local para el archivo GIS.');
|
||||
}
|
||||
|
||||
$input.off('.sigGis');
|
||||
$input.on('adsdropzone:fileadded.sigGis', function (_, file, text) {
|
||||
try {
|
||||
state.file = file;
|
||||
loadGeoJson(state, JSON.parse(text));
|
||||
$(document).trigger('siggis:fileloaded', [state.geojson]);
|
||||
} catch (ex) {
|
||||
state.file = null;
|
||||
state.geojson = null;
|
||||
clearMap(state);
|
||||
renderLinks(state);
|
||||
if (window.ADSLocalDropzone) {
|
||||
window.ADSLocalDropzone.clear(state.options.fileInputId);
|
||||
}
|
||||
showMessage(ex.message || 'El archivo GIS no es válido.', true);
|
||||
}
|
||||
});
|
||||
|
||||
$input.on('adsdropzone:fileremoved.sigGis', function () {
|
||||
state.file = null;
|
||||
state.geojson = null;
|
||||
clearMap(state);
|
||||
renderLinks(state);
|
||||
});
|
||||
}
|
||||
|
||||
function bindSave(state) {
|
||||
$('#' + state.options.saveButtonId)
|
||||
.off('click.sigGis')
|
||||
.on('click.sigGis', function (event) {
|
||||
event.preventDefault();
|
||||
save(state);
|
||||
});
|
||||
}
|
||||
|
||||
api.init = function (options) {
|
||||
var normalized = normalizeOptions(options);
|
||||
var mapElement = document.getElementById(normalized.mapId);
|
||||
if (!mapElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mapElement.getAttribute('data-sig-fraccionamiento-gis-initialized') === '1') {
|
||||
return current;
|
||||
}
|
||||
|
||||
current = createState(normalized);
|
||||
|
||||
try {
|
||||
initMap(current);
|
||||
bindFile(current);
|
||||
bindSave(current);
|
||||
renderLinks(current);
|
||||
mapElement.setAttribute('data-sig-fraccionamiento-gis-initialized', '1');
|
||||
return current;
|
||||
} catch (ex) {
|
||||
console.error(ex);
|
||||
mapElement.removeAttribute('data-sig-fraccionamiento-gis-initialized');
|
||||
showMessage(ex.message || 'No fue posible inicializar el visor GIS.', true);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
api.getState = function () {
|
||||
return current;
|
||||
};
|
||||
|
||||
api.getLinks = function () {
|
||||
return current ? collectLinks(current) : [];
|
||||
};
|
||||
|
||||
api.getLotForPolygon = function (polygonKeyValue) {
|
||||
if (!current) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var lotId = current.linksByPolygonKey[polygonKeyValue];
|
||||
return lotId ? current.lotsById[lotId] || null : null;
|
||||
};
|
||||
|
||||
function autoInit() {
|
||||
if (window.FraccionamientoGISOptions) {
|
||||
api.init(window.FraccionamientoGISOptions);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.Sys && Sys.Application) {
|
||||
if (window.SIG_FRACCIONAMIENTO_GIS_LOAD_REGISTERED !== true) {
|
||||
window.SIG_FRACCIONAMIENTO_GIS_LOAD_REGISTERED = true;
|
||||
Sys.Application.add_load(autoInit);
|
||||
}
|
||||
} else {
|
||||
$(autoInit);
|
||||
}
|
||||
})(window, window.jQuery);
|
||||
14
SIG.Web/Styles/fraccionamiento-gis.css
Normal file
14
SIG.Web/Styles/fraccionamiento-gis.css
Normal file
@@ -0,0 +1,14 @@
|
||||
.sig-gis-map {
|
||||
width: 100%;
|
||||
min-height: 520px;
|
||||
}
|
||||
|
||||
.ads-local-dropzone {
|
||||
min-height: 125px;
|
||||
}
|
||||
|
||||
.sig-gis-links {
|
||||
margin-top: 15px;
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
Reference in New Issue
Block a user